diff --git a/api/api.gen.go b/api/api.gen.go index c0fbf8b1f..ad97c309a 100644 --- a/api/api.gen.go +++ b/api/api.gen.go @@ -144,11 +144,6 @@ const ( CheckoutSessionUIModeHosted CheckoutSessionUIMode = "hosted" ) -// Defines values for DiscountAmountType. -const ( - DiscountAmountTypeAmount DiscountAmountType = "amount" -) - // Defines values for DiscountPercentageType. const ( DiscountPercentageTypePercentage DiscountPercentageType = "percentage" @@ -206,6 +201,11 @@ const ( FlatPriceTypeFlat FlatPriceType = "flat" ) +// Defines values for FlatPriceWithPaymentTermType. +const ( + FlatPriceWithPaymentTermTypeFlat FlatPriceWithPaymentTermType = "flat" +) + // Defines values for GrantOrderBy. const ( GrantOrderByCreatedAt GrantOrderBy = "createdAt" @@ -306,6 +306,29 @@ const ( OpenMeterAppTypeStripe OpenMeterAppType = "stripe" ) +// Defines values for PhasesOrderBy. +const ( + PhasesOrderByKey PhasesOrderBy = "key" +) + +// Defines values for PlanDiscountPercentageType. +const ( + PlanDiscountPercentageTypePercentage PlanDiscountPercentageType = "percentage" +) + +// Defines values for PlanOrderBy. +const ( + PlanOrderById PlanOrderBy = "id" + PlanOrderByKey PlanOrderBy = "key" +) + +// Defines values for PlanStatus. +const ( + PlanStatusActive PlanStatus = "active" + PlanStatusArchived PlanStatus = "archived" + PlanStatusDraft PlanStatus = "draft" +) + // Defines values for PricePaymentTerm. const ( PricePaymentTermInAdvance PricePaymentTerm = "in_advance" @@ -317,6 +340,11 @@ const ( RateCardBooleanEntitlementTypeBoolean RateCardBooleanEntitlementType = "boolean" ) +// Defines values for RateCardFlatFeeType. +const ( + RateCardFlatFeeTypeFlatFee RateCardFlatFeeType = "flat_fee" +) + // Defines values for RateCardMeteredEntitlementType. const ( RateCardMeteredEntitlementTypeMetered RateCardMeteredEntitlementType = "metered" @@ -327,10 +355,9 @@ const ( RateCardStaticEntitlementTypeStatic RateCardStaticEntitlementType = "static" ) -// Defines values for RateCardType. +// Defines values for RateCardUsageBasedType. const ( - RateCardTypeFlatFee RateCardType = "flat_fee" - RateCardTypeUsageBased RateCardType = "usage_based" + RateCardUsageBasedTypeUsageBased RateCardUsageBasedType = "usage_based" ) // Defines values for RecurringPeriodInterval. @@ -378,25 +405,25 @@ const ( SvixOperationalWebhookRequestTypeMessageAttemptRecovered SvixOperationalWebhookRequestType = "message.attempt.recovered" ) -// Defines values for TieredPriceType. -const ( - TieredPriceTypeTiered TieredPriceType = "tiered" -) - // Defines values for TieredPriceMode. const ( TieredPriceModeGraduated TieredPriceMode = "graduated" TieredPriceModeVolume TieredPriceMode = "volume" ) +// Defines values for TieredPriceWithCommitmentsType. +const ( + TieredPriceWithCommitmentsTypeTiered TieredPriceWithCommitmentsType = "tiered" +) + // Defines values for UnitPriceType. const ( UnitPriceTypeUnit UnitPriceType = "unit" ) -// Defines values for UsageDiscountType. +// Defines values for UnitPriceWithCommitmentsType. const ( - UsageDiscountTypeUsage UsageDiscountType = "usage" + UnitPriceWithCommitmentsTypeUnit UnitPriceWithCommitmentsType = "unit" ) // Address Address @@ -607,9 +634,9 @@ type BillingGenericDocumentRef struct { // BillingGenericPaymentTerms defines model for BillingGenericPaymentTerms. type BillingGenericPaymentTerms struct { - Detail *string `json:"detail,omitempty"` - Notes *string `json:"notes,omitempty"` - Type *BillingPaymentTermType `json:"type,omitempty"` + Detail *string `json:"detail,omitempty"` + Notes *string `json:"notes,omitempty"` + Type BillingPaymentTermType `json:"type"` } // BillingInvoiceCreateInput defines model for BillingInvoiceCreateInput. @@ -1262,23 +1289,8 @@ type CustomerUsageAttribution struct { SubjectKeys []string `json:"subjectKeys"` } -// Discount A discount on a price. -// One of: percentage, amount, or usage. -type Discount struct { - union json.RawMessage -} - -// DiscountAmount Amount discount. -type DiscountAmount struct { - // Amount The amount of the discount. - Amount Numeric `json:"amount"` - - // Type The type of the discount. - Type DiscountAmountType `json:"type"` -} - -// DiscountAmountType The type of the discount. -type DiscountAmountType string +// Discount Percentage discount. +type Discount = DiscountPercentage // DiscountPercentage Percentage discount. type DiscountPercentage struct { @@ -1768,8 +1780,19 @@ type FlatPrice struct { // FlatPriceType defines model for FlatPrice.Type. type FlatPriceType string -// FlatPriceWithPaymentTerm Flat price. -type FlatPriceWithPaymentTerm = FlatPrice +// FlatPriceWithPaymentTerm Flat price with payment term. +type FlatPriceWithPaymentTerm struct { + // Amount The amount of the flat price. + Amount Numeric `json:"amount"` + + // PaymentTerm The payment term of the flat price. + // Defaults to in advance. + PaymentTerm *PricePaymentTerm `json:"paymentTerm,omitempty"` + Type FlatPriceWithPaymentTermType `json:"type"` +} + +// FlatPriceWithPaymentTermType defines model for FlatPriceWithPaymentTerm.Type. +type FlatPriceWithPaymentTermType string // ForbiddenProblemResponse A Problem Details object (RFC 7807). // Additional properties specific to the problem type may be present. @@ -2253,6 +2276,248 @@ type Period struct { To time.Time `json:"to"` } +// PhasesOrderBy Order by options for plan phases. +type PhasesOrderBy string + +// Plan Plans provide a template for subscriptions. +type Plan struct { + // CreatedAt Timestamp of when the resource was created. + CreatedAt time.Time `json:"createdAt"` + + // Currency The currency code of the plan. + Currency CurrencyCode `json:"currency"` + + // DeletedAt Timestamp of when the resource was permanently deleted. + DeletedAt *time.Time `json:"deletedAt,omitempty"` + + // Description Optional description of the resource. Maximum 1024 characters. + Description *string `json:"description,omitempty"` + + // EffectiveFrom The date and time when the plan becomes effective. When not specified, the plan is a draft. + EffectiveFrom *time.Time `json:"effectiveFrom,omitempty"` + + // EffectiveTo The date and time when the plan is no longer effective. When not specified, the plan is effective indefinitely. + EffectiveTo *time.Time `json:"effectiveTo,omitempty"` + + // Id A unique identifier for the resource. + Id string `json:"id"` + + // Key A semi-unique identifier for the resource. + Key string `json:"key"` + + // Metadata Additional metadata for the resource. + Metadata *Metadata `json:"metadata,omitempty"` + + // Name Human-readable name for the resource. Between 1 and 256 characters. + Name string `json:"name"` + + // Phases The plan phase or pricing ramp allows changing a plan's rate cards over time as a subscription progresses. + // A phase switch occurs only at the end of a billing period, ensuring that a single subscription invoice will not include charges from different phase prices. + Phases []PlanPhase `json:"phases"` + + // Status The status of the plan. + // Computed based on the effective start and end dates: + // - draft = no effectiveStartDate + // - active = effectiveStartDate <= now < effectiveEndDate + // - archived / inactive = effectiveEndDate <= now + Status PlanStatus `json:"status"` + + // UpdatedAt Timestamp of when the resource was last updated. + UpdatedAt time.Time `json:"updatedAt"` + + // Version Version of the plan. Incremented when the plan is updated. + Version int `json:"version"` +} + +// PlanCreate Resource create operation model. +type PlanCreate struct { + // Currency The currency code of the plan. + Currency CurrencyCode `json:"currency"` + + // Description Optional description of the resource. Maximum 1024 characters. + Description *string `json:"description,omitempty"` + + // EffectiveFrom The date and time when the plan becomes effective. When not specified, the plan is a draft. + EffectiveFrom *time.Time `json:"effectiveFrom,omitempty"` + + // EffectiveTo The date and time when the plan is no longer effective. When not specified, the plan is effective indefinitely. + EffectiveTo *time.Time `json:"effectiveTo,omitempty"` + + // Key A semi-unique identifier for the resource. + Key string `json:"key"` + + // Metadata Additional metadata for the resource. + Metadata *Metadata `json:"metadata,omitempty"` + + // Name Human-readable name for the resource. Between 1 and 256 characters. + Name string `json:"name"` + + // Phases The plan phase or pricing ramp allows changing a plan's rate cards over time as a subscription progresses. + // A phase switch occurs only at the end of a billing period, ensuring that a single subscription invoice will not include charges from different phase prices. + Phases []PlanPhase `json:"phases"` +} + +// PlanDiscount Percentage discount on plan. +type PlanDiscount = PlanDiscountPercentage + +// PlanDiscountPercentage Percentage discount on plan. +type PlanDiscountPercentage struct { + // AppliesToRateCards The rate cards that the discount applies to. + // When not specified, the discount applies to all rate cards. + AppliesToRateCards *[]string `json:"appliesToRateCards,omitempty"` + + // Percentage The percentage of the discount. + Percentage float32 `json:"percentage"` + + // Type The type of the discount. + Type PlanDiscountPercentageType `json:"type"` +} + +// PlanDiscountPercentageType The type of the discount. +type PlanDiscountPercentageType string + +// PlanOrderBy Order by options for plans. +type PlanOrderBy string + +// PlanPaginatedResponse Paginated response +type PlanPaginatedResponse struct { + // Items The items in the current page. + Items []Plan `json:"items"` + + // Page The items in the current page. + Page int `json:"page"` + + // PageSize The items in the current page. + PageSize int `json:"pageSize"` + + // TotalCount The items in the current page. + TotalCount int `json:"totalCount"` +} + +// PlanPhase The plan phase or pricing ramp allows changing a plan's rate cards over time as a subscription progresses. +type PlanPhase struct { + // CreatedAt Timestamp of when the resource was created. + CreatedAt time.Time `json:"createdAt"` + + // DeletedAt Timestamp of when the resource was permanently deleted. + DeletedAt *time.Time `json:"deletedAt,omitempty"` + + // Description Optional description of the resource. Maximum 1024 characters. + Description *string `json:"description,omitempty"` + + // Discount The discount on the plan. + Discount *PlanDiscount `json:"discount,omitempty"` + + // Interval Interval after the subscription starts to transition to the phase. + // When null, the phase starts immediately after the subscription starts. + Interval *string `json:"interval"` + + // Key A semi-unique identifier for the resource. + Key string `json:"key"` + + // Metadata Additional metadata for the resource. + Metadata *Metadata `json:"metadata,omitempty"` + + // Name Human-readable name for the resource. Between 1 and 256 characters. + Name string `json:"name"` + + // RateCards The rate cards of the plan. + RateCards []RateCard `json:"rateCards"` + + // UpdatedAt Timestamp of when the resource was last updated. + UpdatedAt time.Time `json:"updatedAt"` +} + +// PlanPhaseCreate Resource create operation model. +type PlanPhaseCreate struct { + // Description Optional description of the resource. Maximum 1024 characters. + Description *string `json:"description,omitempty"` + + // Discount The discount on the plan. + Discount *PlanDiscount `json:"discount,omitempty"` + + // Interval Interval after the subscription starts to transition to the phase. + // When null, the phase starts immediately after the subscription starts. + Interval *string `json:"interval"` + + // Key A semi-unique identifier for the resource. + Key string `json:"key"` + + // Metadata Additional metadata for the resource. + Metadata *Metadata `json:"metadata,omitempty"` + + // Name Human-readable name for the resource. Between 1 and 256 characters. + Name string `json:"name"` + + // RateCards The rate cards of the plan. + RateCards []RateCard `json:"rateCards"` +} + +// PlanPhasePaginatedResponse Paginated response +type PlanPhasePaginatedResponse struct { + // Items The items in the current page. + Items []PlanPhase `json:"items"` + + // Page The items in the current page. + Page int `json:"page"` + + // PageSize The items in the current page. + PageSize int `json:"pageSize"` + + // TotalCount The items in the current page. + TotalCount int `json:"totalCount"` +} + +// PlanPhaseUpdate Resource create or update operation model. +type PlanPhaseUpdate struct { + // Description Optional description of the resource. Maximum 1024 characters. + Description *string `json:"description,omitempty"` + + // Discount The discount on the plan. + Discount *PlanDiscount `json:"discount,omitempty"` + + // Interval Interval after the subscription starts to transition to the phase. + // When null, the phase starts immediately after the subscription starts. + Interval *string `json:"interval"` + + // Metadata Additional metadata for the resource. + Metadata *Metadata `json:"metadata,omitempty"` + + // Name Human-readable name for the resource. Between 1 and 256 characters. + Name *string `json:"name,omitempty"` + + // RateCards The rate cards of the plan. + RateCards *[]RateCard `json:"rateCards,omitempty"` +} + +// PlanStatus The status of a plan. +type PlanStatus string + +// PlanUpdate Resource create or update operation model. +type PlanUpdate struct { + // Currency The currency code of the plan. + Currency *CurrencyCode `json:"currency,omitempty"` + + // Description Optional description of the resource. Maximum 1024 characters. + Description *string `json:"description,omitempty"` + + // EffectiveFrom The date and time when the plan becomes effective. When not specified, the plan is a draft. + EffectiveFrom *time.Time `json:"effectiveFrom,omitempty"` + + // EffectiveTo The date and time when the plan is no longer effective. When not specified, the plan is effective indefinitely. + EffectiveTo *time.Time `json:"effectiveTo,omitempty"` + + // Metadata Additional metadata for the resource. + Metadata *Metadata `json:"metadata,omitempty"` + + // Name Human-readable name for the resource. Between 1 and 256 characters. + Name *string `json:"name,omitempty"` + + // Phases The plan phase or pricing ramp allows changing a plan's rate cards over time as a subscription progresses. + // A phase switch occurs only at the end of a billing period, ensuring that a single subscription invoice will not include charges from different phase prices. + Phases *[]PlanPhase `json:"phases,omitempty"` +} + // PortalToken A consumer portal token. // // Validator doesn't obey required for readOnly properties @@ -2314,8 +2579,28 @@ type RateCard struct { union json.RawMessage } -// RateCardBase Common fields of the rate card. -type RateCardBase struct { +// RateCardBooleanEntitlement Entitlement template of a boolean entitlement. +type RateCardBooleanEntitlement struct { + // Metadata Additional metadata for the feature. + Metadata *Metadata `json:"metadata,omitempty"` + Type RateCardBooleanEntitlementType `json:"type"` +} + +// RateCardBooleanEntitlementType defines model for RateCardBooleanEntitlement.Type. +type RateCardBooleanEntitlementType string + +// RateCardEntitlement Entitlement templates are used to define the entitlements of a plan. +// Features are omitted from the entitlement template, as they are defined in the rate card. +type RateCardEntitlement struct { + union json.RawMessage +} + +// RateCardFlatFee A flat fee rate card defines a one-time purchase or a recurring fee. +type RateCardFlatFee struct { + // BillingCandence The billing cadence of the rate card. + // When null, the rate card is a one-time purchase. + BillingCandence *string `json:"billingCandence"` + // CreatedAt Timestamp of when the resource was created. CreatedAt time.Time `json:"createdAt"` @@ -2332,8 +2617,8 @@ type RateCardBase struct { // FeatureKey The feature the customer is entitled to use. FeatureKey *string `json:"featureKey,omitempty"` - // Id A unique identifier for the resource. - Id string `json:"id"` + // Key A semi-unique identifier for the resource. + Key string `json:"key"` // Metadata Additional metadata for the resource. Metadata *Metadata `json:"metadata,omitempty"` @@ -2341,35 +2626,23 @@ type RateCardBase struct { // Name Human-readable name for the resource. Between 1 and 256 characters. Name string `json:"name"` + // Price The price of the rate card. + // When null, the feature or service is free. + Price *FlatPriceWithPaymentTerm `json:"price"` + // TaxConfig The tax config of the rate card. // When undefined, the tax config of the feature or the default tax config of the plan is used. TaxConfig *TaxConfig `json:"taxConfig,omitempty"` - // Type The type of the rate card - Type RateCardType `json:"type"` + // Type The type of the RateCard. + Type RateCardFlatFeeType `json:"type"` // UpdatedAt Timestamp of when the resource was last updated. UpdatedAt time.Time `json:"updatedAt"` } -// RateCardBooleanEntitlement Entitlement template of a boolean entitlement. -type RateCardBooleanEntitlement struct { - // Metadata Additional metadata for the feature. - Metadata *Metadata `json:"metadata,omitempty"` - Type RateCardBooleanEntitlementType `json:"type"` -} - -// RateCardBooleanEntitlementType defines model for RateCardBooleanEntitlement.Type. -type RateCardBooleanEntitlementType string - -// RateCardEntitlement Entitlement templates are used to define the entitlements of a plan. -// Features are omitted from the entitlement template, as they are defined in the rate card. -type RateCardEntitlement struct { - union json.RawMessage -} - -// RateCardFlatFee Common fields of the rate card. -type RateCardFlatFee = RateCardBase +// RateCardFlatFeeType The type of the RateCard. +type RateCardFlatFeeType string // RateCardMeteredEntitlement The entitlement template with a metered entitlement. type RateCardMeteredEntitlement struct { @@ -2413,36 +2686,96 @@ type RateCardStaticEntitlement struct { // RateCardStaticEntitlementType defines model for RateCardStaticEntitlement.Type. type RateCardStaticEntitlementType string -// RateCardType The type of the rate card. -type RateCardType string +// RateCardUsageBased A usage-based rate card defines a price based on usage. +type RateCardUsageBased struct { + // BillingCandence The billing cadence of the rate card. + BillingCandence string `json:"billingCandence"` -// RateCardUsageBased Common fields of the rate card. -type RateCardUsageBased = RateCardBase + // CreatedAt Timestamp of when the resource was created. + CreatedAt time.Time `json:"createdAt"` -// RecurringPeriod Recurring period with an interval and an anchor. -type RecurringPeriod struct { - // Anchor A date-time anchor to base the recurring period on. - Anchor time.Time `json:"anchor"` + // DeletedAt Timestamp of when the resource was permanently deleted. + DeletedAt *time.Time `json:"deletedAt,omitempty"` - // Interval The unit of time for the interval. - Interval RecurringPeriodInterval `json:"interval"` -} + // Description Optional description of the resource. Maximum 1024 characters. + Description *string `json:"description,omitempty"` -// RecurringPeriodCreateInput Recurring period with an interval and an anchor. -type RecurringPeriodCreateInput struct { - // Anchor A date-time anchor to base the recurring period on. - Anchor *time.Time `json:"anchor,omitempty"` + // Discount The discount of the rate card. + Discount *Discount `json:"discount,omitempty"` - // Interval The unit of time for the interval. - Interval RecurringPeriodInterval `json:"interval"` -} + // EntitlementTemplate The entitlement of the rate card. + // Only available when featureKey is set. + EntitlementTemplate *RateCardEntitlement `json:"entitlementTemplate,omitempty"` -// RecurringPeriodInterval The unit of time for the interval. -// One of: `day`, `week`, `month`, or `year`. -type RecurringPeriodInterval string + // FeatureKey The feature the customer is entitled to use. + FeatureKey *string `json:"featureKey,omitempty"` -// ResetEntitlementUsageInput Reset parameters -type ResetEntitlementUsageInput struct { + // Key A semi-unique identifier for the resource. + Key string `json:"key"` + + // Metadata Additional metadata for the resource. + Metadata *Metadata `json:"metadata,omitempty"` + + // Name Human-readable name for the resource. Between 1 and 256 characters. + Name string `json:"name"` + + // Price The price of the rate card. + // When null, the feature or service is free. + Price RateCardUsageBased_Price `json:"price"` + + // TaxConfig The tax config of the rate card. + // When undefined, the tax config of the feature or the default tax config of the plan is used. + TaxConfig *TaxConfig `json:"taxConfig,omitempty"` + + // Type The type of the RateCard. + Type RateCardUsageBasedType `json:"type"` + + // UpdatedAt Timestamp of when the resource was last updated. + UpdatedAt time.Time `json:"updatedAt"` +} + +// RateCardUsageBasedPrice0 Unit price with spend commitments. +type RateCardUsageBasedPrice0 = UnitPriceWithCommitments + +// RateCardUsageBasedPrice1 Tiered price with spend commitments. +type RateCardUsageBasedPrice1 = TieredPriceWithCommitments + +// RateCardUsageBasedPrice2 Flat price with payment term. +type RateCardUsageBasedPrice2 = FlatPriceWithPaymentTerm + +// RateCardUsageBased_Price The price of the rate card. +// When null, the feature or service is free. +type RateCardUsageBased_Price struct { + union json.RawMessage +} + +// RateCardUsageBasedType The type of the RateCard. +type RateCardUsageBasedType string + +// RecurringPeriod Recurring period with an interval and an anchor. +type RecurringPeriod struct { + // Anchor A date-time anchor to base the recurring period on. + Anchor time.Time `json:"anchor"` + + // Interval The unit of time for the interval. + Interval RecurringPeriodInterval `json:"interval"` +} + +// RecurringPeriodCreateInput Recurring period with an interval and an anchor. +type RecurringPeriodCreateInput struct { + // Anchor A date-time anchor to base the recurring period on. + Anchor *time.Time `json:"anchor,omitempty"` + + // Interval The unit of time for the interval. + Interval RecurringPeriodInterval `json:"interval"` +} + +// RecurringPeriodInterval The unit of time for the interval. +// One of: `day`, `week`, `month`, or `year`. +type RecurringPeriodInterval string + +// ResetEntitlementUsageInput Reset parameters +type ResetEntitlementUsageInput struct { // EffectiveAt The time at which the reset takes effect, defaults to now. The reset cannot be in the future. The provided value is truncated to the minute due to how historical meter data is stored. EffectiveAt *time.Time `json:"effectiveAt,omitempty"` @@ -2623,8 +2956,17 @@ type TaxConfig struct { } `json:"stripe,omitempty"` } -// TieredPrice Tiered price. -type TieredPrice struct { +// TieredPriceMode The mode of the tiered price. +type TieredPriceMode string + +// TieredPriceWithCommitments Tiered price with spend commitments. +type TieredPriceWithCommitments struct { + // MaximumAmount The customer is limited to spend at most the amount. + MaximumAmount *Numeric `json:"maximumAmount,omitempty"` + + // MinimumAmount The customer is committed to spend at least the amount. + MinimumAmount *Numeric `json:"minimumAmount,omitempty"` + // Mode Defines if the tiering mode is volume-based or graduated: // - In `volume`-based tiering, the maximum quantity within a period determines the per unit price. // - In `graduated` tiering, pricing can change as the quantity grows. @@ -2632,18 +2974,12 @@ type TieredPrice struct { // Tiers The tiers of the tiered price. // At least one price component is required in each tier. - Tiers []PriceTier `json:"tiers"` - Type TieredPriceType `json:"type"` + Tiers []PriceTier `json:"tiers"` + Type TieredPriceWithCommitmentsType `json:"type"` } -// TieredPriceType defines model for TieredPrice.Type. -type TieredPriceType string - -// TieredPriceMode The mode of the tiered price. -type TieredPriceMode string - -// TieredPriceWithCommitments Tiered price. -type TieredPriceWithCommitments = TieredPrice +// TieredPriceWithCommitmentsType defines model for TieredPriceWithCommitments.Type. +type TieredPriceWithCommitmentsType string // UnauthorizedProblemResponse A Problem Details object (RFC 7807). // Additional properties specific to the problem type may be present. @@ -2663,20 +2999,21 @@ type UnitPrice struct { // UnitPriceType defines model for UnitPrice.Type. type UnitPriceType string -// UnitPriceWithCommitments Unit price. -type UnitPriceWithCommitments = UnitPrice +// UnitPriceWithCommitments Unit price with spend commitments. +type UnitPriceWithCommitments struct { + // Amount The amount of the unit price. + Amount Numeric `json:"amount"` -// UsageDiscount Usage discount. -type UsageDiscount struct { - // Type The type of the discount. - Type UsageDiscountType `json:"type"` + // MaximumAmount The customer is limited to spend at most the amount. + MaximumAmount *Numeric `json:"maximumAmount,omitempty"` - // Usage The usage discount. - Usage float64 `json:"usage"` + // MinimumAmount The customer is committed to spend at least the amount. + MinimumAmount *Numeric `json:"minimumAmount,omitempty"` + Type UnitPriceWithCommitmentsType `json:"type"` } -// UsageDiscountType The type of the discount. -type UsageDiscountType string +// UnitPriceWithCommitmentsType defines model for UnitPriceWithCommitments.Type. +type UnitPriceWithCommitmentsType string // WindowSize Aggregation window size. type WindowSize = models.WindowSize @@ -2813,6 +3150,18 @@ type PaginationPage = int // PaginationPageSize defines model for Pagination.pageSize. type PaginationPageSize = int +// PhasesOrderByOrderingOrder The order direction. +type PhasesOrderByOrderingOrder = SortOrder + +// PhasesOrderByOrderingOrderBy Order by options for plan phases. +type PhasesOrderByOrderingOrderBy = PhasesOrderBy + +// PlanOrderByOrderingOrder The order direction. +type PlanOrderByOrderingOrder = SortOrder + +// PlanOrderByOrderingOrderBy Order by options for plans. +type PlanOrderByOrderingOrderBy = PlanOrderBy + // ProfileOrderByOrderingOrder The order direction. type ProfileOrderByOrderingOrder = SortOrder @@ -3334,6 +3683,61 @@ type ListNotificationRulesParams struct { OrderBy *NotificationRuleOrderByOrderingOrderBy `form:"orderBy,omitempty" json:"orderBy,omitempty"` } +// ListPlansParams defines parameters for ListPlans. +type ListPlansParams struct { + // IncludeDeleted Include deleted plans in response. + // + // Usage: `?includeDeleted=true` + IncludeDeleted *bool `form:"includeDeleted,omitempty" json:"includeDeleted,omitempty"` + + // Id Filter by plan.id attribute + Id *[]string `form:"id,omitempty" json:"id,omitempty"` + + // Key Filter by plan.key attribute + Key *[]string `form:"key,omitempty" json:"key,omitempty"` + + // KeyVersion Filter by plan.key and plan.version attributes + KeyVersion *map[string]int `json:"keyVersion,omitempty"` + + // Page Start date-time in RFC 3339 format. + // + // Inclusive. + Page *PaginationPage `form:"page,omitempty" json:"page,omitempty"` + + // PageSize Number of items per page. + // + // Default is 100. + PageSize *PaginationPageSize `form:"pageSize,omitempty" json:"pageSize,omitempty"` + + // Order The order direction. + Order *PlanOrderByOrderingOrder `form:"order,omitempty" json:"order,omitempty"` + + // OrderBy The order by field. + OrderBy *PlanOrderByOrderingOrderBy `form:"orderBy,omitempty" json:"orderBy,omitempty"` +} + +// ListPlanPhasesParams defines parameters for ListPlanPhases. +type ListPlanPhasesParams struct { + // Key Filter by phase.key attribute + Key *[]string `form:"key,omitempty" json:"key,omitempty"` + + // Page Start date-time in RFC 3339 format. + // + // Inclusive. + Page *PaginationPage `form:"page,omitempty" json:"page,omitempty"` + + // PageSize Number of items per page. + // + // Default is 100. + PageSize *PaginationPageSize `form:"pageSize,omitempty" json:"pageSize,omitempty"` + + // Order The order direction. + Order *PhasesOrderByOrderingOrder `form:"order,omitempty" json:"order,omitempty"` + + // OrderBy The order by field. + OrderBy *PhasesOrderByOrderingOrderBy `form:"orderBy,omitempty" json:"orderBy,omitempty"` +} + // QueryPortalMeterParams defines parameters for QueryPortalMeter. type QueryPortalMeterParams struct { // From Start date-time in RFC 3339 format. @@ -3473,6 +3877,18 @@ type UpdateNotificationRuleJSONRequestBody = NotificationRuleCreateRequest // ReceiveSvixOperationalEventJSONRequestBody defines body for ReceiveSvixOperationalEvent for application/json ContentType. type ReceiveSvixOperationalEventJSONRequestBody = SvixOperationalWebhookRequest +// CreatePlanJSONRequestBody defines body for CreatePlan for application/json ContentType. +type CreatePlanJSONRequestBody = PlanCreate + +// UpdatePlanJSONRequestBody defines body for UpdatePlan for application/json ContentType. +type UpdatePlanJSONRequestBody = PlanUpdate + +// CreatePlanPhasesJSONRequestBody defines body for CreatePlanPhases for application/json ContentType. +type CreatePlanPhasesJSONRequestBody = PlanPhaseCreate + +// UpdatePlanPhasesJSONRequestBody defines body for UpdatePlanPhases for application/json ContentType. +type UpdatePlanPhasesJSONRequestBody = PlanPhaseUpdate + // CreatePortalTokenJSONRequestBody defines body for CreatePortalToken for application/json ContentType. type CreatePortalTokenJSONRequestBody = PortalToken @@ -3618,125 +4034,6 @@ func (t *CreateStripeCheckoutSessionRequest_Customer) UnmarshalJSON(b []byte) er return err } -// AsDiscountPercentage returns the union data inside the Discount as a DiscountPercentage -func (t Discount) AsDiscountPercentage() (DiscountPercentage, error) { - var body DiscountPercentage - err := json.Unmarshal(t.union, &body) - return body, err -} - -// FromDiscountPercentage overwrites any union data inside the Discount as the provided DiscountPercentage -func (t *Discount) FromDiscountPercentage(v DiscountPercentage) error { - v.Type = "percentage" - b, err := json.Marshal(v) - t.union = b - return err -} - -// MergeDiscountPercentage performs a merge with any union data inside the Discount, using the provided DiscountPercentage -func (t *Discount) MergeDiscountPercentage(v DiscountPercentage) error { - v.Type = "percentage" - b, err := json.Marshal(v) - if err != nil { - return err - } - - merged, err := runtime.JSONMerge(t.union, b) - t.union = merged - return err -} - -// AsDiscountAmount returns the union data inside the Discount as a DiscountAmount -func (t Discount) AsDiscountAmount() (DiscountAmount, error) { - var body DiscountAmount - err := json.Unmarshal(t.union, &body) - return body, err -} - -// FromDiscountAmount overwrites any union data inside the Discount as the provided DiscountAmount -func (t *Discount) FromDiscountAmount(v DiscountAmount) error { - v.Type = "amount" - b, err := json.Marshal(v) - t.union = b - return err -} - -// MergeDiscountAmount performs a merge with any union data inside the Discount, using the provided DiscountAmount -func (t *Discount) MergeDiscountAmount(v DiscountAmount) error { - v.Type = "amount" - b, err := json.Marshal(v) - if err != nil { - return err - } - - merged, err := runtime.JSONMerge(t.union, b) - t.union = merged - return err -} - -// AsUsageDiscount returns the union data inside the Discount as a UsageDiscount -func (t Discount) AsUsageDiscount() (UsageDiscount, error) { - var body UsageDiscount - err := json.Unmarshal(t.union, &body) - return body, err -} - -// FromUsageDiscount overwrites any union data inside the Discount as the provided UsageDiscount -func (t *Discount) FromUsageDiscount(v UsageDiscount) error { - v.Type = "usage" - b, err := json.Marshal(v) - t.union = b - return err -} - -// MergeUsageDiscount performs a merge with any union data inside the Discount, using the provided UsageDiscount -func (t *Discount) MergeUsageDiscount(v UsageDiscount) error { - v.Type = "usage" - b, err := json.Marshal(v) - if err != nil { - return err - } - - merged, err := runtime.JSONMerge(t.union, b) - t.union = merged - return err -} - -func (t Discount) Discriminator() (string, error) { - var discriminator struct { - Discriminator string `json:"type"` - } - err := json.Unmarshal(t.union, &discriminator) - return discriminator.Discriminator, err -} - -func (t Discount) ValueByDiscriminator() (interface{}, error) { - discriminator, err := t.Discriminator() - if err != nil { - return nil, err - } - switch discriminator { - case "amount": - return t.AsDiscountAmount() - case "percentage": - return t.AsDiscountPercentage() - case "usage": - return t.AsUsageDiscount() - default: - return nil, errors.New("unknown discriminator value: " + discriminator) - } -} - -func (t Discount) MarshalJSON() ([]byte, error) { - b, err := t.union.MarshalJSON() - return b, err -} - -func (t *Discount) UnmarshalJSON(b []byte) error { - err := t.union.UnmarshalJSON(b) - return err -} - // AsEntitlementMetered returns the union data inside the Entitlement as a EntitlementMetered func (t Entitlement) AsEntitlementMetered() (EntitlementMetered, error) { var body EntitlementMetered @@ -4245,6 +4542,94 @@ func (t *RateCardEntitlement) UnmarshalJSON(b []byte) error { return err } +// AsRateCardUsageBasedPrice0 returns the union data inside the RateCardUsageBased_Price as a RateCardUsageBasedPrice0 +func (t RateCardUsageBased_Price) AsRateCardUsageBasedPrice0() (RateCardUsageBasedPrice0, error) { + var body RateCardUsageBasedPrice0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromRateCardUsageBasedPrice0 overwrites any union data inside the RateCardUsageBased_Price as the provided RateCardUsageBasedPrice0 +func (t *RateCardUsageBased_Price) FromRateCardUsageBasedPrice0(v RateCardUsageBasedPrice0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeRateCardUsageBasedPrice0 performs a merge with any union data inside the RateCardUsageBased_Price, using the provided RateCardUsageBasedPrice0 +func (t *RateCardUsageBased_Price) MergeRateCardUsageBasedPrice0(v RateCardUsageBasedPrice0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsRateCardUsageBasedPrice1 returns the union data inside the RateCardUsageBased_Price as a RateCardUsageBasedPrice1 +func (t RateCardUsageBased_Price) AsRateCardUsageBasedPrice1() (RateCardUsageBasedPrice1, error) { + var body RateCardUsageBasedPrice1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromRateCardUsageBasedPrice1 overwrites any union data inside the RateCardUsageBased_Price as the provided RateCardUsageBasedPrice1 +func (t *RateCardUsageBased_Price) FromRateCardUsageBasedPrice1(v RateCardUsageBasedPrice1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeRateCardUsageBasedPrice1 performs a merge with any union data inside the RateCardUsageBased_Price, using the provided RateCardUsageBasedPrice1 +func (t *RateCardUsageBased_Price) MergeRateCardUsageBasedPrice1(v RateCardUsageBasedPrice1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsRateCardUsageBasedPrice2 returns the union data inside the RateCardUsageBased_Price as a RateCardUsageBasedPrice2 +func (t RateCardUsageBased_Price) AsRateCardUsageBasedPrice2() (RateCardUsageBasedPrice2, error) { + var body RateCardUsageBasedPrice2 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromRateCardUsageBasedPrice2 overwrites any union data inside the RateCardUsageBased_Price as the provided RateCardUsageBasedPrice2 +func (t *RateCardUsageBased_Price) FromRateCardUsageBasedPrice2(v RateCardUsageBasedPrice2) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeRateCardUsageBasedPrice2 performs a merge with any union data inside the RateCardUsageBased_Price, using the provided RateCardUsageBasedPrice2 +func (t *RateCardUsageBased_Price) MergeRateCardUsageBasedPrice2(v RateCardUsageBasedPrice2) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t RateCardUsageBased_Price) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *RateCardUsageBased_Price) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // ServerInterface represents all server handlers. type ServerInterface interface { @@ -4448,6 +4833,45 @@ type ServerInterface interface { // Receive Svix operational events // (POST /api/v1/notification/webhook/svix) ReceiveSvixOperationalEvent(w http.ResponseWriter, r *http.Request) + // List plans + // (GET /api/v1/plans) + ListPlans(w http.ResponseWriter, r *http.Request, params ListPlansParams) + // Create a plan + // (POST /api/v1/plans) + CreatePlan(w http.ResponseWriter, r *http.Request) + // Delete plan + // (DELETE /api/v1/plans/{planId}) + DeletePlan(w http.ResponseWriter, r *http.Request, planId string) + // Get plan + // (GET /api/v1/plans/{planId}) + GetPlan(w http.ResponseWriter, r *http.Request, planId string) + // Update a plan + // (PUT /api/v1/plans/{planId}) + UpdatePlan(w http.ResponseWriter, r *http.Request, planId string) + // New draft plan + // (POST /api/v1/plans/{planId}/next) + NewDraftPlan(w http.ResponseWriter, r *http.Request, planId string) + // List phases in plan + // (GET /api/v1/plans/{planId}/phases) + ListPlanPhases(w http.ResponseWriter, r *http.Request, planId string, params ListPlanPhasesParams) + // Create new phase in plan + // (POST /api/v1/plans/{planId}/phases) + CreatePlanPhases(w http.ResponseWriter, r *http.Request, planId string) + // Delete phase for plan + // (DELETE /api/v1/plans/{planId}/phases/{planPhaseKey}) + DeletePlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) + // Get phase for plan + // (GET /api/v1/plans/{planId}/phases/{planPhaseKey}) + GetPlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) + // Update phase in plan + // (PUT /api/v1/plans/{planId}/phases/{planPhaseKey}) + UpdatePlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) + // Publish plan + // (POST /api/v1/plans/{planId}/publish) + PublishPlan(w http.ResponseWriter, r *http.Request, planId string) + // Unpublish plan + // (POST /api/v1/plans/{planId}/unpublish) + UnpublishPlan(w http.ResponseWriter, r *http.Request, planId string) // (GET /api/v1/portal/meters/{meterSlug}/query) QueryPortalMeter(w http.ResponseWriter, r *http.Request, meterSlug string, params QueryPortalMeterParams) @@ -4879,7 +5303,85 @@ func (_ Unimplemented) ReceiveSvixOperationalEvent(w http.ResponseWriter, r *htt w.WriteHeader(http.StatusNotImplemented) } -// (GET /api/v1/portal/meters/{meterSlug}/query) +// List plans +// (GET /api/v1/plans) +func (_ Unimplemented) ListPlans(w http.ResponseWriter, r *http.Request, params ListPlansParams) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Create a plan +// (POST /api/v1/plans) +func (_ Unimplemented) CreatePlan(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Delete plan +// (DELETE /api/v1/plans/{planId}) +func (_ Unimplemented) DeletePlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Get plan +// (GET /api/v1/plans/{planId}) +func (_ Unimplemented) GetPlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Update a plan +// (PUT /api/v1/plans/{planId}) +func (_ Unimplemented) UpdatePlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// New draft plan +// (POST /api/v1/plans/{planId}/next) +func (_ Unimplemented) NewDraftPlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// List phases in plan +// (GET /api/v1/plans/{planId}/phases) +func (_ Unimplemented) ListPlanPhases(w http.ResponseWriter, r *http.Request, planId string, params ListPlanPhasesParams) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Create new phase in plan +// (POST /api/v1/plans/{planId}/phases) +func (_ Unimplemented) CreatePlanPhases(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Delete phase for plan +// (DELETE /api/v1/plans/{planId}/phases/{planPhaseKey}) +func (_ Unimplemented) DeletePlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Get phase for plan +// (GET /api/v1/plans/{planId}/phases/{planPhaseKey}) +func (_ Unimplemented) GetPlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Update phase in plan +// (PUT /api/v1/plans/{planId}/phases/{planPhaseKey}) +func (_ Unimplemented) UpdatePlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Publish plan +// (POST /api/v1/plans/{planId}/publish) +func (_ Unimplemented) PublishPlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Unpublish plan +// (POST /api/v1/plans/{planId}/unpublish) +func (_ Unimplemented) UnpublishPlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// (GET /api/v1/portal/meters/{meterSlug}/query) func (_ Unimplemented) QueryPortalMeter(w http.ResponseWriter, r *http.Request, meterSlug string, params QueryPortalMeterParams) { w.WriteHeader(http.StatusNotImplemented) } @@ -7986,6 +8488,552 @@ func (siw *ServerInterfaceWrapper) ReceiveSvixOperationalEvent(w http.ResponseWr handler.ServeHTTP(w, r) } +// ListPlans operation middleware +func (siw *ServerInterfaceWrapper) ListPlans(w http.ResponseWriter, r *http.Request) { + + var err error + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + // Parameter object where we will unmarshal all parameters from the context + var params ListPlansParams + + // ------------- Optional query parameter "includeDeleted" ------------- + + err = runtime.BindQueryParameter("form", false, false, "includeDeleted", r.URL.Query(), ¶ms.IncludeDeleted) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "includeDeleted", Err: err}) + return + } + + // ------------- Optional query parameter "id" ------------- + + err = runtime.BindQueryParameter("form", true, false, "id", r.URL.Query(), ¶ms.Id) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + // ------------- Optional query parameter "key" ------------- + + err = runtime.BindQueryParameter("form", true, false, "key", r.URL.Query(), ¶ms.Key) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "key", Err: err}) + return + } + + // ------------- Optional query parameter "keyVersion" ------------- + + err = runtime.BindQueryParameter("deepObject", true, false, "keyVersion", r.URL.Query(), ¶ms.KeyVersion) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "keyVersion", Err: err}) + return + } + + // ------------- Optional query parameter "page" ------------- + + err = runtime.BindQueryParameter("form", false, false, "page", r.URL.Query(), ¶ms.Page) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "page", Err: err}) + return + } + + // ------------- Optional query parameter "pageSize" ------------- + + err = runtime.BindQueryParameter("form", false, false, "pageSize", r.URL.Query(), ¶ms.PageSize) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "pageSize", Err: err}) + return + } + + // ------------- Optional query parameter "order" ------------- + + err = runtime.BindQueryParameter("form", false, false, "order", r.URL.Query(), ¶ms.Order) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "order", Err: err}) + return + } + + // ------------- Optional query parameter "orderBy" ------------- + + err = runtime.BindQueryParameter("form", false, false, "orderBy", r.URL.Query(), ¶ms.OrderBy) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "orderBy", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListPlans(w, r, params) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// CreatePlan operation middleware +func (siw *ServerInterfaceWrapper) CreatePlan(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreatePlan(w, r) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// DeletePlan operation middleware +func (siw *ServerInterfaceWrapper) DeletePlan(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeletePlan(w, r, planId) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// GetPlan operation middleware +func (siw *ServerInterfaceWrapper) GetPlan(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetPlan(w, r, planId) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdatePlan operation middleware +func (siw *ServerInterfaceWrapper) UpdatePlan(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdatePlan(w, r, planId) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// NewDraftPlan operation middleware +func (siw *ServerInterfaceWrapper) NewDraftPlan(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.NewDraftPlan(w, r, planId) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// ListPlanPhases operation middleware +func (siw *ServerInterfaceWrapper) ListPlanPhases(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + // Parameter object where we will unmarshal all parameters from the context + var params ListPlanPhasesParams + + // ------------- Optional query parameter "key" ------------- + + err = runtime.BindQueryParameter("form", true, false, "key", r.URL.Query(), ¶ms.Key) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "key", Err: err}) + return + } + + // ------------- Optional query parameter "page" ------------- + + err = runtime.BindQueryParameter("form", false, false, "page", r.URL.Query(), ¶ms.Page) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "page", Err: err}) + return + } + + // ------------- Optional query parameter "pageSize" ------------- + + err = runtime.BindQueryParameter("form", false, false, "pageSize", r.URL.Query(), ¶ms.PageSize) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "pageSize", Err: err}) + return + } + + // ------------- Optional query parameter "order" ------------- + + err = runtime.BindQueryParameter("form", false, false, "order", r.URL.Query(), ¶ms.Order) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "order", Err: err}) + return + } + + // ------------- Optional query parameter "orderBy" ------------- + + err = runtime.BindQueryParameter("form", false, false, "orderBy", r.URL.Query(), ¶ms.OrderBy) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "orderBy", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListPlanPhases(w, r, planId, params) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// CreatePlanPhases operation middleware +func (siw *ServerInterfaceWrapper) CreatePlanPhases(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreatePlanPhases(w, r, planId) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// DeletePlanPhases operation middleware +func (siw *ServerInterfaceWrapper) DeletePlanPhases(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + // ------------- Path parameter "planPhaseKey" ------------- + var planPhaseKey string + + err = runtime.BindStyledParameterWithOptions("simple", "planPhaseKey", chi.URLParam(r, "planPhaseKey"), &planPhaseKey, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planPhaseKey", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeletePlanPhases(w, r, planId, planPhaseKey) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// GetPlanPhases operation middleware +func (siw *ServerInterfaceWrapper) GetPlanPhases(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + // ------------- Path parameter "planPhaseKey" ------------- + var planPhaseKey string + + err = runtime.BindStyledParameterWithOptions("simple", "planPhaseKey", chi.URLParam(r, "planPhaseKey"), &planPhaseKey, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planPhaseKey", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetPlanPhases(w, r, planId, planPhaseKey) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdatePlanPhases operation middleware +func (siw *ServerInterfaceWrapper) UpdatePlanPhases(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + // ------------- Path parameter "planPhaseKey" ------------- + var planPhaseKey string + + err = runtime.BindStyledParameterWithOptions("simple", "planPhaseKey", chi.URLParam(r, "planPhaseKey"), &planPhaseKey, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planPhaseKey", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdatePlanPhases(w, r, planId, planPhaseKey) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// PublishPlan operation middleware +func (siw *ServerInterfaceWrapper) PublishPlan(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.PublishPlan(w, r, planId) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +// UnpublishPlan operation middleware +func (siw *ServerInterfaceWrapper) UnpublishPlan(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "planId" ------------- + var planId string + + err = runtime.BindStyledParameterWithOptions("simple", "planId", chi.URLParam(r, "planId"), &planId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "planId", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, CloudTokenAuthScopes, []string{}) + + ctx = context.WithValue(ctx, CloudCookieAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UnpublishPlan(w, r, planId) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + // QueryPortalMeter operation middleware func (siw *ServerInterfaceWrapper) QueryPortalMeter(w http.ResponseWriter, r *http.Request) { @@ -9058,6 +10106,45 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/api/v1/notification/webhook/svix", wrapper.ReceiveSvixOperationalEvent) }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/api/v1/plans", wrapper.ListPlans) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/api/v1/plans", wrapper.CreatePlan) + }) + r.Group(func(r chi.Router) { + r.Delete(options.BaseURL+"/api/v1/plans/{planId}", wrapper.DeletePlan) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/api/v1/plans/{planId}", wrapper.GetPlan) + }) + r.Group(func(r chi.Router) { + r.Put(options.BaseURL+"/api/v1/plans/{planId}", wrapper.UpdatePlan) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/api/v1/plans/{planId}/next", wrapper.NewDraftPlan) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/api/v1/plans/{planId}/phases", wrapper.ListPlanPhases) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/api/v1/plans/{planId}/phases", wrapper.CreatePlanPhases) + }) + r.Group(func(r chi.Router) { + r.Delete(options.BaseURL+"/api/v1/plans/{planId}/phases/{planPhaseKey}", wrapper.DeletePlanPhases) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/api/v1/plans/{planId}/phases/{planPhaseKey}", wrapper.GetPlanPhases) + }) + r.Group(func(r chi.Router) { + r.Put(options.BaseURL+"/api/v1/plans/{planId}/phases/{planPhaseKey}", wrapper.UpdatePlanPhases) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/api/v1/plans/{planId}/publish", wrapper.PublishPlan) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/api/v1/plans/{planId}/unpublish", wrapper.UnpublishPlan) + }) r.Group(func(r chi.Router) { r.Get(options.BaseURL+"/api/v1/portal/meters/{meterSlug}/query", wrapper.QueryPortalMeter) }) @@ -9119,583 +10206,612 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "tl0FAA==", + "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", + "BgA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/openapi.yaml b/api/openapi.yaml index a83b7c6d9..a12142bb5 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -15,6 +15,7 @@ tags: - name: Entitlements (Experimental) - name: Customers - name: Billing (Experimental) + - name: Plan (Experimental) - name: Events - name: Meters - name: Debug @@ -4578,35 +4579,66 @@ paths: application/json: schema: $ref: '#/components/schemas/SvixOperationalWebhookRequest' - /api/v1/portal/meters/{meterSlug}/query: + /api/v1/plans: get: - operationId: queryPortalMeter + operationId: listPlans + summary: List plans + description: List all plans. parameters: - - name: meterSlug - in: path - required: true + - name: includeDeleted + in: query + required: false + description: |- + Include deleted plans in response. + + Usage: `?includeDeleted=true` schema: - type: string - minLength: 1 - maxLength: 64 - pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ - - $ref: '#/components/parameters/MeterQuery.from' - - $ref: '#/components/parameters/MeterQuery.to' - - $ref: '#/components/parameters/MeterQuery.windowSize' - - $ref: '#/components/parameters/MeterQuery.windowTimeZone' - - $ref: '#/components/parameters/MeterQuery.filterGroupBy' - - $ref: '#/components/parameters/MeterQuery.groupBy' - description: Query meter for consumer portal. This endpoint is publicly exposable to consumers. Query meter for consumer portal. This endpoint is publicly exposable to consumers. + type: boolean + default: false + explode: false + - name: id + in: query + required: false + description: Filter by plan.id attribute + schema: + type: array + items: + type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: ULID (Universally Unique Lexicographically Sortable Identifier). + - name: key + in: query + required: false + description: Filter by plan.key attribute + schema: + type: array + items: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A key is a unique string that is used to identify a resource. + - name: keyVersion + in: query + required: false + description: Filter by plan.key and plan.version attributes + schema: + type: object + additionalProperties: + type: integer + style: deepObject + - $ref: '#/components/parameters/Pagination.page' + - $ref: '#/components/parameters/Pagination.pageSize' + - $ref: '#/components/parameters/PlanOrderByOrdering.order' + - $ref: '#/components/parameters/PlanOrderByOrdering.orderBy' responses: '200': description: The request has succeeded. content: application/json: schema: - $ref: '#/components/schemas/MeterQueryResult' - text/csv: - schema: - type: string + $ref: '#/components/schemas/PlanPaginatedResponse' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -4625,12 +4657,6 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' - '404': - description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. - content: - application/problem+json: - schema: - $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -4650,22 +4676,19 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Portal - security: - - PortalTokenAuth: [] - - CloudPortalTokenAuth: [] - /api/v1/portal/tokens: + - Plan (Experimental) post: - operationId: createPortalToken - description: Create a consumer portal token. + operationId: createPlan + summary: Create a plan + description: Create a new plan. parameters: [] responses: - '200': - description: The request has succeeded. + '201': + description: The request has succeeded and a new resource has been created as a result. content: application/json: schema: - $ref: '#/components/schemas/PortalToken' + $ref: '#/components/schemas/Plan' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -4703,35 +4726,33 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Portal + - Plan (Experimental) requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/PortalToken' - get: - operationId: listPortalTokens - description: List tokens. + $ref: '#/components/schemas/PlanCreate' + /api/v1/plans/{planId}: + put: + operationId: updatePlan + summary: Update a plan + description: Update plan by id. parameters: - - name: limit - in: query - required: false + - name: planId + in: path + required: true schema: - type: integer - minimum: 1 - maximum: 100 - default: 25 - explode: false + type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ responses: '200': description: The request has succeeded. content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/PortalToken' + $ref: '#/components/schemas/Plan' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -4750,6 +4771,12 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -4769,15 +4796,41 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Portal - /api/v1/portal/tokens/invalidate: - post: - operationId: invalidatePortalTokens - description: Invalidates consumer portal tokens by ID or subject. - parameters: [] + - Plan (Experimental) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PlanUpdate' + get: + operationId: getPlan + summary: Get plan + description: Get a plan by id or key. The latest published version is returned if latter is used. + parameters: + - name: planId + in: path + required: true + schema: + anyOf: + - type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: ULID (Universally Unique Lexicographically Sortable Identifier). + - type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A key is a unique string that is used to identify a resource. + x-go-type: string + x-go-type: string responses: - '204': - description: 'There is no content to send for this request, but the headers may be useful. ' + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/Plan' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -4796,6 +4849,12 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -4815,34 +4874,25 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Portal - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - id: - type: string - description: Invalidate a portal token by ID. - subject: - type: string - description: Invalidate all portal tokens for a subject. - /api/v1/subjects: - get: - operationId: listSubjects - description: List subjects. - parameters: [] + - Plan (Experimental) + delete: + operationId: deletePlan + summary: Delete plan + description: |- + Soft delete plan by plan.id. + + Once a plan is deleted it cannot be undeleted. + parameters: + - name: planId + in: path + required: true + schema: + type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ responses: - '200': - description: The request has succeeded. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Subject' + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -4861,6 +4911,12 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -4880,24 +4936,38 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Subjects + - Plan (Experimental) + /api/v1/plans/{planId}/next: post: - operationId: upsertSubject + operationId: newDraftPlan + summary: New draft plan description: |- - Upserts a subject. Creates or updates subject. - - If the subject doesn't exist, it will be created. - If the subject exists, it will be partially updated with the provided fields. - parameters: [] + Create a new draft version from plan. + It returns error if there is already a plan in draft or planId does not reference the latest published version. + parameters: + - name: planId + in: path + required: true + schema: + anyOf: + - type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: ULID (Universally Unique Lexicographically Sortable Identifier). + - type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A key is a unique string that is used to identify a resource. + x-go-type: string + x-go-type: string responses: - '200': - description: The request has succeeded. + '201': + description: The request has succeeded and a new resource has been created as a result. content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/Subject' + $ref: '#/components/schemas/Plan' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -4916,6 +4986,12 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -4935,32 +5011,43 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Subjects - requestBody: - required: true - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/SubjectUpsert' - /api/v1/subjects/{subjectIdOrKey}: + - Plan (Experimental) + /api/v1/plans/{planId}/phases: get: - operationId: getSubject - description: Get subject by ID or key. + operationId: listPlanPhases + summary: List phases in plan + description: List all phases in plan. parameters: - - name: subjectIdOrKey + - name: planId in: path required: true schema: type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + - name: key + in: query + required: false + description: Filter by phase.key attribute + schema: + type: array + items: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A key is a unique string that is used to identify a resource. + - $ref: '#/components/parameters/Pagination.page' + - $ref: '#/components/parameters/Pagination.pageSize' + - $ref: '#/components/parameters/PhasesOrderByOrdering.order' + - $ref: '#/components/parameters/PhasesOrderByOrdering.orderBy' responses: '200': description: The request has succeeded. content: application/json: schema: - $ref: '#/components/schemas/Subject' + $ref: '#/components/schemas/PlanPhasePaginatedResponse' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -4979,12 +5066,6 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' - '404': - description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. - content: - application/problem+json: - schema: - $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5004,19 +5085,26 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Subjects - delete: - operationId: deleteSubject - description: Delete subject by ID or key. + - Plan (Experimental) + post: + operationId: createPlanPhases + summary: Create new phase in plan + description: Create new phase in plan. parameters: - - name: subjectIdOrKey + - name: planId in: path required: true schema: type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ responses: - '204': - description: 'There is no content to send for this request, but the headers may be useful. ' + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/PlanPhase' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5054,34 +5142,41 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Subjects - /api/v1/subjects/{subjectIdOrKey}/entitlements: - post: - operationId: createEntitlement - summary: Create an entitlement - description: |- - OpenMeter has three types of entitlements: metered, boolean, and static. The type property determines the type of entitlement. The underlying feature has to be compatible with the entitlement type specified in the request (e.g., a metered entitlement needs a feature associated with a meter). - - - Boolean entitlements define static feature access, e.g. "Can use SSO authentication". - - Static entitlements let you pass along a configuration while granting access, e.g. "Using this feature with X Y settings" (passed in the config). - - Metered entitlements have many use cases, from setting up usage-based access to implementing complex credit systems. Example: The customer can use 10000 AI tokens during the usage period of the entitlement. - - A given subject can only have one active (non-deleted) entitlement per featureKey. If you try to create a new entitlement for a featureKey that already has an active entitlement, the request will fail with a 409 error. - - Once an entitlement is created you cannot modify it, only delete it. + - Plan (Experimental) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PlanPhaseCreate' + /api/v1/plans/{planId}/phases/{planPhaseKey}: + put: + operationId: updatePlanPhases + summary: Update phase in plan + description: Update phase in plan. parameters: - - name: subjectIdOrKey + - name: planId + in: path + required: true + schema: + type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + - name: planPhaseKey in: path required: true schema: type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ responses: - '201': - description: The request has succeeded and a new resource has been created as a result. + '200': + description: The request has succeeded. content: application/json: schema: - $ref: '#/components/schemas/EntitlementCreateInputs' + $ref: '#/components/schemas/PlanPhase' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5100,12 +5195,12 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' - '409': - description: The request could not be completed due to a conflict with the current state of the target resource. + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. content: application/problem+json: schema: - $ref: '#/components/schemas/ConflictProblemResponse' + $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5125,38 +5220,40 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) + - Plan (Experimental) requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/EntitlementCreateInputs' + $ref: '#/components/schemas/PlanPhaseUpdate' get: - operationId: listSubjectEntitlements - description: List all entitlements for a subject. For checking entitlement access, use the /value endpoint instead. + operationId: getPlanPhases + summary: Get phase for plan + description: Get phase in plan. parameters: - - name: subjectIdOrKey + - name: planId in: path required: true schema: type: string - - name: includeDeleted - in: query - required: false + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + - name: planPhaseKey + in: path + required: true schema: - type: boolean - default: false - explode: false + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ responses: '200': description: The request has succeeded. content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/Entitlement' + $ref: '#/components/schemas/PlanPhase' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5175,6 +5272,12 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5194,45 +5297,33 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) - /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementIdOrFeatureKey}/grants: - get: - operationId: listEntitlementGrants - description: List all grants issued for an entitlement. The entitlement can be defined either by its id or featureKey. + - Plan (Experimental) + delete: + operationId: deletePlanPhases + summary: Delete phase for plan + description: |- + Delete phase in plan. + + Once a phase is deleted it cannot be undeleted. parameters: - - name: subjectIdOrKey + - name: planId in: path required: true schema: type: string - - name: entitlementIdOrFeatureKey + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + - name: planPhaseKey in: path required: true schema: type: string - - name: includeDeleted - in: query - required: false - schema: - type: boolean - default: false - explode: false - - name: orderBy - in: query - required: false - schema: - $ref: '#/components/schemas/GrantOrderBy' - default: updatedAt - explode: false + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ responses: - '200': - description: The request has succeeded. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/EntitlementGrant' + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5251,6 +5342,12 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5270,39 +5367,23 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) + - Plan (Experimental) + /api/v1/plans/{planId}/publish: post: - operationId: createGrant - description: |- - Grants define a behavior of granting usage for a metered entitlement. They can have complicated recurrence and rollover rules, thanks to which you can define a wide range of access patterns with a single grant, in most cases you don't have to periodically create new grants. You can only issue grants for active metered entitlements. - - A grant defines a given amount of usage that can be consumed for the entitlement. The grant is in effect between its effective date and its expiration date. Specifying both is mandatory for new grants. - - Grants have a priority setting that determines their order of use. Lower numbers have higher priority, with 0 being the highest priority. - - Grants can have a recurrence setting intended to automate the manual reissuing of grants. For example, a daily recurrence is equal to reissuing that same grant every day (ignoring rollover settings). - - Rollover settings define what happens to the remaining balance of a grant at a reset. Balance_After_Reset = MIN(MaxRolloverAmount, MAX(Balance_Before_Reset, MinRolloverAmount)) - - Grants cannot be changed once created, only deleted. This is to ensure that balance is deterministic regardless of when it is queried. + operationId: publishPlan + summary: Publish plan + description: Publish a new plan. parameters: - - name: subjectIdOrKey - in: path - required: true - schema: - type: string - - name: entitlementIdOrFeatureKey + - name: planId in: path required: true schema: type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ responses: - '201': - description: The request has succeeded and a new resource has been created as a result. - content: - application/json: - schema: - $ref: '#/components/schemas/EntitlementGrant' + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5321,12 +5402,12 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' - '409': - description: The request could not be completed due to a conflict with the current state of the target resource. + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. content: application/problem+json: schema: - $ref: '#/components/schemas/ConflictProblemResponse' + $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5346,38 +5427,23 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/EntitlementGrantCreateInput' - /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementIdOrFeatureKey}/override: - put: - operationId: overrideEntitlement - description: |- - Overriding an entitlement creates a new entitlement from the provided inputs and soft deletes the previous entitlement for the provided subject-feature pair. If the previous entitlement is already deleted or otherwise doesnt exist, the override will fail. - - This endpoint is useful for upgrades, downgrades, or other changes to entitlements that require a new entitlement to be created with zero downtime. + - Plan (Experimental) + /api/v1/plans/{planId}/unpublish: + post: + operationId: unpublishPlan + summary: Unpublish plan + description: Unpublish a new plan. parameters: - - name: subjectIdOrKey - in: path - required: true - schema: - type: string - - name: entitlementIdOrFeatureKey + - name: planId in: path required: true schema: type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ responses: - '201': - description: The request has succeeded and a new resource has been created as a result. - content: - application/json: - schema: - $ref: '#/components/schemas/Entitlement' + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5402,12 +5468,6 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/NotFoundProblemResponse' - '409': - description: The request could not be completed due to a conflict with the current state of the target resource. - content: - application/problem+json: - schema: - $ref: '#/components/schemas/ConflictProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5427,45 +5487,36 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/EntitlementCreateInputs' - /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementIdOrFeatureKey}/value: + - Plan (Experimental) + /api/v1/portal/meters/{meterSlug}/query: get: - operationId: getEntitlementValue - description: |- - This endpoint should be used for access checks and enforcement. All entitlement types share the hasAccess property in their value response, but multiple other properties are returned based on the entitlement type. - - For convenience reasons, /value works with both entitlementId and featureKey. + operationId: queryPortalMeter parameters: - - name: subjectIdOrKey - in: path - required: true - schema: - type: string - - name: entitlementIdOrFeatureKey + - name: meterSlug in: path required: true schema: type: string - - name: time - in: query - required: false - schema: - type: string - format: date-time - example: 2023-01-01T01:01:01.001Z + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + - $ref: '#/components/parameters/MeterQuery.from' + - $ref: '#/components/parameters/MeterQuery.to' + - $ref: '#/components/parameters/MeterQuery.windowSize' + - $ref: '#/components/parameters/MeterQuery.windowTimeZone' + - $ref: '#/components/parameters/MeterQuery.filterGroupBy' + - $ref: '#/components/parameters/MeterQuery.groupBy' + description: Query meter for consumer portal. This endpoint is publicly exposable to consumers. Query meter for consumer portal. This endpoint is publicly exposable to consumers. responses: '200': description: The request has succeeded. content: application/json: schema: - $ref: '#/components/schemas/EntitlementValue' + $ref: '#/components/schemas/MeterQueryResult' + text/csv: + schema: + type: string '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5509,29 +5560,22 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) - /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId}: - get: - operationId: getEntitlement - description: Get entitlement by id. For checking entitlement access, use the /value endpoint instead. - parameters: - - name: subjectIdOrKey - in: path - required: true - schema: - type: string - - name: entitlementId - in: path - required: true - schema: - type: string + - Portal + security: + - PortalTokenAuth: [] + - CloudPortalTokenAuth: [] + /api/v1/portal/tokens: + post: + operationId: createPortalToken + description: Create a consumer portal token. + parameters: [] responses: '200': description: The request has succeeded. content: application/json: schema: - $ref: '#/components/schemas/Entitlement' + $ref: '#/components/schemas/PortalToken' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5550,12 +5594,6 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' - '404': - description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. - content: - application/problem+json: - schema: - $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5575,26 +5613,35 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) - delete: - operationId: deleteEntitlement - description: |- - Deleting an entitlement revokes access to the associated feature. As a single subject can only have one entitlement per featureKey, when "migrating" features you have to delete the old entitlements as well. - As access and status checks can be historical queries, deleting an entitlement populates the deletedAt timestamp. When queried for a time before that, the entitlement is still considered active, you cannot have retroactive changes to access, which is important for, among other things, auditing. + - Portal + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PortalToken' + get: + operationId: listPortalTokens + description: List tokens. parameters: - - name: subjectIdOrKey - in: path - required: true - schema: - type: string - - name: entitlementId - in: path - required: true + - name: limit + in: query + required: false schema: - type: string + type: integer + minimum: 1 + maximum: 100 + default: 25 + explode: false responses: - '204': - description: 'There is no content to send for this request, but the headers may be useful. ' + '200': + description: The request has succeeded. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PortalToken' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5613,12 +5660,52 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' - '404': - description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: application/problem+json: schema: - $ref: '#/components/schemas/NotFoundProblemResponse' + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Portal + /api/v1/portal/tokens/invalidate: + post: + operationId: invalidatePortalTokens + description: Invalidates consumer portal tokens by ID or subject. + parameters: [] + responses: + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5638,65 +5725,34 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) - /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId}/history: + - Portal + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + id: + type: string + description: Invalidate a portal token by ID. + subject: + type: string + description: Invalidate all portal tokens for a subject. + /api/v1/subjects: get: - operationId: getEntitlementHistory - description: |- - Returns historical balance and usage data for the entitlement. The queried history can span accross multiple reset events. - - BurndownHistory returns a continous history of segments, where the segments are seperated by events that changed either the grant burndown priority or the usage period. - - WindowedHistory returns windowed usage data for the period enriched with balance information and the list of grants that were being burnt down in that window. - parameters: - - name: subjectIdOrKey - in: path - required: true - schema: - type: string - - name: entitlementId - in: path - required: true - schema: - type: string - - name: from - in: query - required: false - description: 'Start of time range to query entitlement: date-time in RFC 3339 format. Defaults to the last reset. Gets truncated to the granularity of the underlying meter.' - schema: - type: string - format: date-time - example: 2023-01-01T01:01:01.001Z - - name: to - in: query - required: false - description: |- - End of time range to query entitlement: date-time in RFC 3339 format. Defaults to now. - If not now then gets truncated to the granularity of the underlying meter. - schema: - type: string - format: date-time - example: 2023-01-01T01:01:01.001Z - - name: windowSize - in: query - required: true - description: Windowsize - schema: - $ref: '#/components/schemas/WindowSize' - - name: windowTimeZone - in: query - required: false - description: The timezone used when calculating the windows. - schema: - type: string - default: UTC + operationId: listSubjects + description: List subjects. + parameters: [] responses: '200': description: The request has succeeded. content: application/json: schema: - $ref: '#/components/schemas/WindowedBalanceHistory' + type: array + items: + $ref: '#/components/schemas/Subject' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5715,12 +5771,6 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ForbiddenProblemResponse' - '404': - description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. - content: - application/problem+json: - schema: - $ref: '#/components/schemas/NotFoundProblemResponse' '500': description: The server encountered an unexpected condition that prevented it from fulfilling the request. content: @@ -5740,28 +5790,87 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) - /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId}/reset: + - Subjects post: - operationId: resetEntitlementUsage + operationId: upsertSubject description: |- - Reset marks the start of a new usage period for the entitlement and initiates grant rollover. At the start of a period usage is zerod out and grants are rolled over based on their rollover settings. It would typically be synced with the subjects billing period to enforce usage based on their subscription. + Upserts a subject. Creates or updates subject. - Usage is automatically reset for metered entitlements based on their usage period, but this endpoint allows to manually reset it at any time. When doing so the period anchor of the entitlement can be changed if needed. + If the subject doesn't exist, it will be created. + If the subject exists, it will be partially updated with the provided fields. + parameters: [] + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Subject' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Subjects + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SubjectUpsert' + /api/v1/subjects/{subjectIdOrKey}: + get: + operationId: getSubject + description: Get subject by ID or key. parameters: - name: subjectIdOrKey in: path required: true schema: type: string - - name: entitlementId - in: path - required: true - schema: - type: string responses: - '204': - description: 'There is no content to send for this request, but the headers may be useful. ' + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/Subject' '400': description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). content: @@ -5805,15 +5914,816 @@ paths: schema: $ref: '#/components/schemas/UnexpectedProblemResponse' tags: - - Entitlements (Experimental) - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResetEntitlementUsageInput' -security: - - {} + - Subjects + delete: + operationId: deleteSubject + description: Delete subject by ID or key. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + responses: + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Subjects + /api/v1/subjects/{subjectIdOrKey}/entitlements: + post: + operationId: createEntitlement + summary: Create an entitlement + description: |- + OpenMeter has three types of entitlements: metered, boolean, and static. The type property determines the type of entitlement. The underlying feature has to be compatible with the entitlement type specified in the request (e.g., a metered entitlement needs a feature associated with a meter). + + - Boolean entitlements define static feature access, e.g. "Can use SSO authentication". + - Static entitlements let you pass along a configuration while granting access, e.g. "Using this feature with X Y settings" (passed in the config). + - Metered entitlements have many use cases, from setting up usage-based access to implementing complex credit systems. Example: The customer can use 10000 AI tokens during the usage period of the entitlement. + + A given subject can only have one active (non-deleted) entitlement per featureKey. If you try to create a new entitlement for a featureKey that already has an active entitlement, the request will fail with a 409 error. + + Once an entitlement is created you cannot modify it, only delete it. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + responses: + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/EntitlementCreateInputs' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '409': + description: The request could not be completed due to a conflict with the current state of the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ConflictProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EntitlementCreateInputs' + get: + operationId: listSubjectEntitlements + description: List all entitlements for a subject. For checking entitlement access, use the /value endpoint instead. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: includeDeleted + in: query + required: false + schema: + type: boolean + default: false + explode: false + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Entitlement' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementIdOrFeatureKey}/grants: + get: + operationId: listEntitlementGrants + description: List all grants issued for an entitlement. The entitlement can be defined either by its id or featureKey. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: entitlementIdOrFeatureKey + in: path + required: true + schema: + type: string + - name: includeDeleted + in: query + required: false + schema: + type: boolean + default: false + explode: false + - name: orderBy + in: query + required: false + schema: + $ref: '#/components/schemas/GrantOrderBy' + default: updatedAt + explode: false + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EntitlementGrant' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + post: + operationId: createGrant + description: |- + Grants define a behavior of granting usage for a metered entitlement. They can have complicated recurrence and rollover rules, thanks to which you can define a wide range of access patterns with a single grant, in most cases you don't have to periodically create new grants. You can only issue grants for active metered entitlements. + + A grant defines a given amount of usage that can be consumed for the entitlement. The grant is in effect between its effective date and its expiration date. Specifying both is mandatory for new grants. + + Grants have a priority setting that determines their order of use. Lower numbers have higher priority, with 0 being the highest priority. + + Grants can have a recurrence setting intended to automate the manual reissuing of grants. For example, a daily recurrence is equal to reissuing that same grant every day (ignoring rollover settings). + + Rollover settings define what happens to the remaining balance of a grant at a reset. Balance_After_Reset = MIN(MaxRolloverAmount, MAX(Balance_Before_Reset, MinRolloverAmount)) + + Grants cannot be changed once created, only deleted. This is to ensure that balance is deterministic regardless of when it is queried. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: entitlementIdOrFeatureKey + in: path + required: true + schema: + type: string + responses: + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/EntitlementGrant' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '409': + description: The request could not be completed due to a conflict with the current state of the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ConflictProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EntitlementGrantCreateInput' + /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementIdOrFeatureKey}/override: + put: + operationId: overrideEntitlement + description: |- + Overriding an entitlement creates a new entitlement from the provided inputs and soft deletes the previous entitlement for the provided subject-feature pair. If the previous entitlement is already deleted or otherwise doesnt exist, the override will fail. + + This endpoint is useful for upgrades, downgrades, or other changes to entitlements that require a new entitlement to be created with zero downtime. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: entitlementIdOrFeatureKey + in: path + required: true + schema: + type: string + responses: + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/Entitlement' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' + '409': + description: The request could not be completed due to a conflict with the current state of the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ConflictProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EntitlementCreateInputs' + /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementIdOrFeatureKey}/value: + get: + operationId: getEntitlementValue + description: |- + This endpoint should be used for access checks and enforcement. All entitlement types share the hasAccess property in their value response, but multiple other properties are returned based on the entitlement type. + + For convenience reasons, /value works with both entitlementId and featureKey. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: entitlementIdOrFeatureKey + in: path + required: true + schema: + type: string + - name: time + in: query + required: false + schema: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/EntitlementValue' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId}: + get: + operationId: getEntitlement + description: Get entitlement by id. For checking entitlement access, use the /value endpoint instead. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: entitlementId + in: path + required: true + schema: + type: string + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/Entitlement' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + delete: + operationId: deleteEntitlement + description: |- + Deleting an entitlement revokes access to the associated feature. As a single subject can only have one entitlement per featureKey, when "migrating" features you have to delete the old entitlements as well. + As access and status checks can be historical queries, deleting an entitlement populates the deletedAt timestamp. When queried for a time before that, the entitlement is still considered active, you cannot have retroactive changes to access, which is important for, among other things, auditing. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: entitlementId + in: path + required: true + schema: + type: string + responses: + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId}/history: + get: + operationId: getEntitlementHistory + description: |- + Returns historical balance and usage data for the entitlement. The queried history can span accross multiple reset events. + + BurndownHistory returns a continous history of segments, where the segments are seperated by events that changed either the grant burndown priority or the usage period. + + WindowedHistory returns windowed usage data for the period enriched with balance information and the list of grants that were being burnt down in that window. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: entitlementId + in: path + required: true + schema: + type: string + - name: from + in: query + required: false + description: 'Start of time range to query entitlement: date-time in RFC 3339 format. Defaults to the last reset. Gets truncated to the granularity of the underlying meter.' + schema: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + - name: to + in: query + required: false + description: |- + End of time range to query entitlement: date-time in RFC 3339 format. Defaults to now. + If not now then gets truncated to the granularity of the underlying meter. + schema: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + - name: windowSize + in: query + required: true + description: Windowsize + schema: + $ref: '#/components/schemas/WindowSize' + - name: windowTimeZone + in: query + required: false + description: The timezone used when calculating the windows. + schema: + type: string + default: UTC + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/WindowedBalanceHistory' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId}/reset: + post: + operationId: resetEntitlementUsage + description: |- + Reset marks the start of a new usage period for the entitlement and initiates grant rollover. At the start of a period usage is zerod out and grants are rolled over based on their rollover settings. It would typically be synced with the subjects billing period to enforce usage based on their subscription. + + Usage is automatically reset for metered entitlements based on their usage period, but this endpoint allows to manually reset it at any time. When doing so the period anchor of the entitlement can be changed if needed. + parameters: + - name: subjectIdOrKey + in: path + required: true + schema: + type: string + - name: entitlementId + in: path + required: true + schema: + type: string + responses: + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' + '400': + description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestProblemResponse' + '401': + description: The request has not been applied because it lacks valid authentication credentials for the target resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedProblemResponse' + '403': + description: The server understood the request but refuses to authorize it. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenProblemResponse' + '404': + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/NotFoundProblemResponse' + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/InternalServerErrorProblemResponse' + '503': + description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ServiceUnavailableProblemResponse' + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnexpectedProblemResponse' + tags: + - Entitlements (Experimental) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResetEntitlementUsageInput' +security: + - {} - CloudTokenAuth: [] - CloudCookieAuth: [] components: @@ -6197,6 +7107,38 @@ components: maximum: 1000 default: 100 explode: false + PhasesOrderByOrdering.order: + name: order + in: query + required: false + description: The order direction. + schema: + $ref: '#/components/schemas/SortOrder' + explode: false + PhasesOrderByOrdering.orderBy: + name: orderBy + in: query + required: false + description: The order by field. + schema: + $ref: '#/components/schemas/PhasesOrderBy' + explode: false + PlanOrderByOrdering.order: + name: order + in: query + required: false + description: The order direction. + schema: + $ref: '#/components/schemas/SortOrder' + explode: false + PlanOrderByOrdering.orderBy: + name: orderBy + in: query + required: false + description: The order by field. + schema: + $ref: '#/components/schemas/PlanOrderBy' + explode: false ProfileOrderByOrdering.order: name: order in: query @@ -6648,6 +7590,8 @@ components: title: DocumentRef is used to describe an existing document or a specific part of it's contents. BillingGenericPaymentTerms: type: object + required: + - type properties: type: allOf: @@ -8046,37 +8990,12 @@ components: One customer can have multiple subjects, but one subject can only belong to one customer. Discount: - anyOf: + type: object + allOf: - $ref: '#/components/schemas/DiscountPercentage' - - $ref: '#/components/schemas/DiscountAmount' - - $ref: '#/components/schemas/UsageDiscount' - discriminator: - propertyName: type - mapping: - percentage: '#/components/schemas/DiscountPercentage' - amount: '#/components/schemas/DiscountAmount' - usage: '#/components/schemas/UsageDiscount' description: |- A discount on a price. One of: percentage, amount, or usage. - DiscountAmount: - type: object - required: - - type - - amount - properties: - type: - type: string - enum: - - amount - description: The type of the discount. - title: Type - amount: - allOf: - - $ref: '#/components/schemas/Numeric' - description: The amount of the discount. - title: Amount - description: Amount discount. DiscountPercentage: type: object required: @@ -9169,7 +10088,18 @@ components: description: Flat price. FlatPriceWithPaymentTerm: type: object + required: + - type + - amount properties: + type: + type: string + enum: + - flat + amount: + allOf: + - $ref: '#/components/schemas/Numeric' + description: The amount of the flat price. paymentTerm: allOf: - $ref: '#/components/schemas/PricePaymentTerm' @@ -9177,8 +10107,6 @@ components: The payment term of the flat price. Defaults to in advance. default: in_advance - allOf: - - $ref: '#/components/schemas/FlatPrice' description: Flat price with payment term. ForbiddenProblemResponse: type: object @@ -9288,65 +10216,407 @@ components: items: type: array items: - $ref: '#/components/schemas/EntitlementGrant' + $ref: '#/components/schemas/EntitlementGrant' + description: The items in the current page. + description: Paginated response + GrantUsageRecord: + type: object + required: + - grantId + - usage + properties: + grantId: + type: string + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: The id of the grant + usage: + type: number + format: double + example: 100 + description: The usage in the period + description: Usage Record + IngestedEvent: + type: object + required: + - event + - ingestedAt + - storedAt + properties: + event: + $ref: '#/components/schemas/Event' + validationError: + type: string + description: The validation error if the event failed validation. + ingestedAt: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: The date and time the event was ingested. + storedAt: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: The date and time the event was stored. + example: + event: + id: 5c10fade-1c9e-4d6c-8275-c52c36731d3c + source: service-name + specversion: '1.0' + type: prompt + subject: customer-id + time: 2023-01-01T01:01:01.001Z + ingestedAt: 2023-01-01T01:01:01.001Z + storedAt: 2023-01-01T01:01:02.001Z + description: An ingested event with optional validation error. + InternalServerErrorProblemResponse: + type: object + allOf: + - $ref: '#/components/schemas/UnexpectedProblemResponse' + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + InvoicePaginatedResponse: + type: object + required: + - totalCount + - page + - pageSize + - items + properties: + totalCount: + type: integer + example: 500 + description: The items in the current page. + page: + type: integer + example: 1 + description: The items in the current page. + pageSize: + type: integer + example: 100 + description: The items in the current page. + items: + type: array + items: + $ref: '#/components/schemas/BillingInvoiceSummary' description: The items in the current page. description: Paginated response - GrantUsageRecord: + MarketplaceListing: type: object required: - - grantId - - usage + - type + - name + - description + - iconUrl + - capabilities properties: - grantId: + type: + allOf: + - $ref: '#/components/schemas/OpenMeter.App.Type' + description: The app's type + name: + type: string + description: The app's name. + description: + type: string + description: The app's description. + iconUrl: + type: string + description: The app's icon URL. + capabilities: + type: array + items: + $ref: '#/components/schemas/AppCapability' + description: The app's capabilities. + example: + type: stripe + name: Stripe + description: Stripe interation allows you to collect payments with Stripe. + iconUrl: /images/stripe.png + capabilities: + - type: calculateTax + key: stripe_calculate_tax + name: Calculate Tax + description: Stripe Tax calculates tax portion of the invoices. + - type: invoiceCustomers + key: stripe_invoice_customers + name: Invoice Customers + description: Stripe invoices customers with due amount. + - type: collectPayments + key: stripe_collect_payments + name: Collect Payments + description: Stripe payments collects outstanding revenue with Stripe customer's default payment method. + description: |- + A marketplace listing. + Represent an available app in the app marketplace that can be installed to the organization. + + Marketplace apps only exist in config so they don't extend the Resource model. + MarketplaceListingList: + type: object + required: + - page + - pageSize + - totalCount + - items + properties: + page: + type: integer + description: The page number. + pageSize: + type: integer + minimum: 1 + maximum: 1000 + description: The number of items in the page. + totalCount: + type: integer + description: The total number of items. + items: + type: array + items: + $ref: '#/components/schemas/MarketplaceListing' + maxItems: 1000 + description: The items in the page. + description: A page of results. + MeasureUsageFrom: + oneOf: + - $ref: '#/components/schemas/MeasureUsageFromPreset' + - $ref: '#/components/schemas/MeasureUsageFromTime' + description: Measure usage from + MeasureUsageFromPreset: + type: string + enum: + - CURRENT_PERIOD_START + - NOW + description: Start of measurement options + x-enum-varnames: + - CurrentPeriodStart + - Now + MeasureUsageFromTime: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' + Metadata: + type: object + additionalProperties: + type: string + example: + externalId: 019142cc-a016-796a-8113-1a942fecd26d + description: |- + Set of key-value pairs. + Metadata can be used to store additional information about a resource. + x-go-type: map[string]string + Meter: + type: object + required: + - id + - slug + - aggregation + - windowSize + - eventType + properties: + id: type: string example: 01G65Z755AFWAKHE12NY0CQ9FH pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: The id of the grant - usage: - type: number - format: double - example: 100 - description: The usage in the period - description: Usage Record - IngestedEvent: + description: A unique identifier for the meter. + readOnly: true + slug: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: |- + A unique, human-readable identifier for the meter. + Must consist only alphanumeric and underscore characters. + example: tokens_total + description: + type: string + example: AI Token Usage + minLength: 1 + description: A description of the meter. + aggregation: + allOf: + - $ref: '#/components/schemas/MeterAggregation' + example: SUM + windowSize: + allOf: + - $ref: '#/components/schemas/WindowSize' + example: MINUTE + eventType: + type: string + example: prompt + minLength: 1 + description: The event type to aggregate. + valueProperty: + type: string + example: $.tokens + minLength: 1 + description: |- + JSONPath expression to extract the value from the ingested event's data property. + + The ingested value for SUM, AVG, MIN, and MAX aggregations is a number or a string that can be parsed to a number. + + For UNIQUE_COUNT aggregation, the ingested value must be a string. For COUNT aggregation the valueProperty is ignored. + groupBy: + type: object + additionalProperties: + type: string + example: + type: $.type + description: |- + Named JSONPath expressions to extract the group by values from the event data. + + Keys must be unique and consist only alphanumeric and underscore characters. + + TODO: add key format enforcement + example: + id: 01G65Z755AFWAKHE12NY0CQ9FH + slug: tokens_total + description: AI Token Usage + aggregation: SUM + windowSize: MINUTE + eventType: prompt + valueProperty: $.tokens + groupBy: + model: $.model + type: $.type + description: A meter is a configuration that defines how to match and aggregate events. + x-go-type-import: + path: github.com/openmeterio/openmeter/pkg/models + x-go-type: models.Meter + MeterAggregation: + type: string + enum: + - SUM + - COUNT + - UNIQUE_COUNT + - AVG + - MIN + - MAX + description: The aggregation type to use for the meter. + x-go-type-import: + path: github.com/openmeterio/openmeter/pkg/models + x-go-type: models.MeterAggregation + MeterQueryResult: type: object required: - - event - - ingestedAt - - storedAt + - data properties: - event: - $ref: '#/components/schemas/Event' - validationError: + from: type: string - description: The validation error if the event failed validation. - ingestedAt: + format: date-time + example: 2023-01-01T01:01:01.001Z + description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' + to: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' + windowSize: + $ref: '#/components/schemas/WindowSize' + data: + type: array + items: + $ref: '#/components/schemas/MeterQueryRow' + example: + from: 2023-01-01T00:00:00Z + to: 2023-01-02T00:00:00Z + windowSize: DAY + data: + - value: 12 + windowStart: 2023-01-01T00:00:00Z + windowEnd: 2023-01-02T00:00:00Z + subject: customer-1 + groupBy: + model: gpt-4-turbo + type: prompt + description: The result of a meter query. + MeterQueryRow: + type: object + required: + - value + - windowStart + - windowEnd + properties: + value: + type: number + windowStart: type: string format: date-time example: 2023-01-01T01:01:01.001Z - description: The date and time the event was ingested. - storedAt: + description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' + windowEnd: type: string format: date-time example: 2023-01-01T01:01:01.001Z - description: The date and time the event was stored. + description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' + subject: + type: string + groupBy: + type: object + additionalProperties: + type: string example: - event: - id: 5c10fade-1c9e-4d6c-8275-c52c36731d3c - source: service-name - specversion: '1.0' + value: 12 + windowStart: 2023-01-01T00:00:00Z + windowEnd: 2023-01-02T00:00:00Z + subject: customer-1 + groupBy: + model: gpt-4-turbo type: prompt - subject: customer-id - time: 2023-01-01T01:01:01.001Z - ingestedAt: 2023-01-01T01:01:01.001Z - storedAt: 2023-01-01T01:01:02.001Z - description: An ingested event with optional validation error. - InternalServerErrorProblemResponse: + description: A row in the result of a meter query. + x-go-type-import: + path: github.com/openmeterio/openmeter/pkg/models + x-go-type: models.MeterQueryRow + NotFoundProblemResponse: type: object allOf: - $ref: '#/components/schemas/UnexpectedProblemResponse' - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - InvoicePaginatedResponse: + description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. + NotImplementedProblemResponse: + type: object + allOf: + - $ref: '#/components/schemas/UnexpectedProblemResponse' + description: The server does not support the functionality required to fulfill the request. + NotificationChannel: + type: object + allOf: + - $ref: '#/components/schemas/NotificationChannelWebhook' + description: Notification channel. + NotificationChannelCreateRequest: + type: object + allOf: + - $ref: '#/components/schemas/NotificationChannelWebhookCreateRequest' + description: Union type for requests creating new notification channel with certain type. + NotificationChannelMeta: + type: object + required: + - id + - type + properties: + id: + type: string + example: 01ARZ3NDEKTSV4RRFFQ69G5FAV + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: Identifies the notification channel. + title: Channel Unique Identifier + readOnly: true + type: + allOf: + - $ref: '#/components/schemas/NotificationChannelType' + description: Notification channel type. + title: Channel Type + readOnly: true + description: Metadata only fields of a notification channel. + NotificationChannelOrderBy: + type: string + enum: + - id + - type + - createdAt + - updatedAt + description: Order by options for notification channels. + NotificationChannelPaginatedResponse: type: object required: - totalCount @@ -9369,318 +10639,530 @@ components: items: type: array items: - $ref: '#/components/schemas/BillingInvoiceSummary' + $ref: '#/components/schemas/NotificationChannel' description: The items in the current page. description: Paginated response - MarketplaceListing: + NotificationChannelType: + type: string + enum: + - WEBHOOK + description: Type of the notification channel. + x-enum-varnames: + - Webhook + NotificationChannelWebhook: type: object required: + - createdAt + - updatedAt + - id - type - name - - description - - iconUrl - - capabilities + - url properties: + createdAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was created. + title: Creation Time + readOnly: true + updatedAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was last updated. + title: Last Update Time + readOnly: true + deletedAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was permanently deleted. + title: Deletion Time + readOnly: true + id: + type: string + example: 01ARZ3NDEKTSV4RRFFQ69G5FAV + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: Identifies the notification channel. + title: Channel Unique Identifier + readOnly: true type: - allOf: - - $ref: '#/components/schemas/OpenMeter.App.Type' - description: The app's type + type: string + enum: + - WEBHOOK + description: Notification channel type. + title: Channel Type name: type: string - description: The app's name. - description: + example: customer-webhook + description: User friendly name of the channel. + title: Channel Name + disabled: + type: boolean + example: true + description: Whether the channel is disabled or not. + title: Channel Disabled + default: false + url: type: string - description: The app's description. - iconUrl: + example: https://example.com/webhook + description: Webhook URL where the notification is sent. + title: Webhook URL + customHeaders: + type: object + additionalProperties: + type: string + description: Custom HTTP headers sent as part of the webhook request. + title: Custom HTTP Headers + signingSecret: type: string - description: The app's icon URL. - capabilities: - type: array - items: - $ref: '#/components/schemas/AppCapability' - description: The app's capabilities. - example: - type: stripe - name: Stripe - description: Stripe interation allows you to collect payments with Stripe. - iconUrl: /images/stripe.png - capabilities: - - type: calculateTax - key: stripe_calculate_tax - name: Calculate Tax - description: Stripe Tax calculates tax portion of the invoices. - - type: invoiceCustomers - key: stripe_invoice_customers - name: Invoice Customers - description: Stripe invoices customers with due amount. - - type: collectPayments - key: stripe_collect_payments - name: Collect Payments - description: Stripe payments collects outstanding revenue with Stripe customer's default payment method. - description: |- - A marketplace listing. - Represent an available app in the app marketplace that can be installed to the organization. + example: whsec_S6g2HLnTwd9AhHwUIMFggVS9OfoPafN8 + pattern: ^(whsec_)?[a-zA-Z0-9+/=]{32,100}$ + description: |- + Signing secret used for webhook request validation on the receiving end. - Marketplace apps only exist in config so they don't extend the Resource model. - MarketplaceListingList: + Format: `base64` encoded random bytes optionally prefixed with `whsec_`. Recommended size: 24 + title: Signing Secret + description: Notification channel with webhook type. + NotificationChannelWebhookCreateRequest: type: object required: - - page - - pageSize - - totalCount - - items + - type + - name + - url properties: - page: - type: integer - description: The page number. - pageSize: - type: integer - minimum: 1 - maximum: 1000 - description: The number of items in the page. - totalCount: - type: integer - description: The total number of items. - items: + type: + type: string + enum: + - WEBHOOK + description: Notification channel type. + title: Channel Type + name: + type: string + example: customer-webhook + description: User friendly name of the channel. + title: Channel Name + disabled: + type: boolean + example: true + description: Whether the channel is disabled or not. + title: Channel Disabled + default: false + url: + type: string + example: https://example.com/webhook + description: Webhook URL where the notification is sent. + title: Webhook URL + customHeaders: + type: object + additionalProperties: + type: string + description: Custom HTTP headers sent as part of the webhook request. + title: Custom HTTP Headers + signingSecret: + type: string + example: whsec_S6g2HLnTwd9AhHwUIMFggVS9OfoPafN8 + pattern: ^(whsec_)?[a-zA-Z0-9+/=]{32,100}$ + description: |- + Signing secret used for webhook request validation on the receiving end. + + Format: `base64` encoded random bytes optionally prefixed with `whsec_`. Recommended size: 24 + title: Signing Secret + description: Request with input parameters for creating new notification channel with webhook type. + NotificationEvent: + type: object + required: + - id + - type + - createdAt + - rule + - deliveryStatus + - payload + properties: + id: + type: string + example: 01J2KNP1YTXQRXHTDJ4KPR7PZ0 + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: A unique identifier of the notification event. + title: Event Identifier + readOnly: true + type: + allOf: + - $ref: '#/components/schemas/NotificationEventType' + description: Type of the notification event. + title: Event Type + readOnly: true + createdAt: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: Timestamp when the notification event was created in RFC 3339 format. + title: Creation Time + readOnly: true + rule: + allOf: + - $ref: '#/components/schemas/NotificationRule' + description: The nnotification rule which generated this event. + title: Owner Rule + readOnly: true + deliveryStatus: type: array items: - $ref: '#/components/schemas/MarketplaceListing' - maxItems: 1000 - description: The items in the page. - description: A page of results. - MeasureUsageFrom: - oneOf: - - $ref: '#/components/schemas/MeasureUsageFromPreset' - - $ref: '#/components/schemas/MeasureUsageFromTime' - description: Measure usage from - MeasureUsageFromPreset: - type: string - enum: - - CURRENT_PERIOD_START - - NOW - description: Start of measurement options - x-enum-varnames: - - CurrentPeriodStart - - Now - MeasureUsageFromTime: - type: string - format: date-time - example: 2023-01-01T01:01:01.001Z - description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' - Metadata: - type: object - additionalProperties: - type: string - example: - externalId: 019142cc-a016-796a-8113-1a942fecd26d - description: |- - Set of key-value pairs. - Metadata can be used to store additional information about a resource. - x-go-type: map[string]string - Meter: + $ref: '#/components/schemas/NotificationEventDeliveryStatus' + description: The delivery status of the notification event. + title: Delivery Status + readOnly: true + payload: + allOf: + - $ref: '#/components/schemas/NotificationEventPayload' + description: Timestamp when the notification event was created in RFC 3339 format. + title: Event Payload + readOnly: true + annotations: + allOf: + - $ref: '#/components/schemas/Annotations' + description: Set of key-value pairs managed by the system. Cannot be modified by user. + title: Annotations + readOnly: true + description: Type of the notification event. + NotificationEventBalanceThresholdPayload: type: object required: - id - - slug - - aggregation - - windowSize - - eventType + - type + - timestamp + - data properties: id: type: string - example: 01G65Z755AFWAKHE12NY0CQ9FH + example: 01J2KNP1YTXQRXHTDJ4KPR7PZ0 pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: A unique identifier for the meter. + description: A unique identifier for the notification event the payload belongs to. + title: Notification Event Identifier readOnly: true - slug: + type: type: string - minLength: 1 - maxLength: 64 - pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ - description: |- - A unique, human-readable identifier for the meter. - Must consist only alphanumeric and underscore characters. - example: tokens_total - description: + enum: + - entitlements.balance.threshold + description: Type of the notification event. + title: Notification Event Type + readOnly: true + timestamp: type: string - example: AI Token Usage - minLength: 1 - description: A description of the meter. - aggregation: + format: date-time + example: 2023-01-01T01:01:01.001Z + description: Timestamp when the notification event was created in RFC 3339 format. + title: Creation Time + readOnly: true + data: allOf: - - $ref: '#/components/schemas/MeterAggregation' - example: SUM - windowSize: + - $ref: '#/components/schemas/NotificationEventBalanceThresholdPayloadData' + description: The data of the payload. + title: Payload Data + readOnly: true + description: Payload for notification event with `entitlements.balance.threshold` type. + NotificationEventBalanceThresholdPayloadData: + type: object + required: + - entitlement + - feature + - subject + - value + - threshold + properties: + entitlement: allOf: - - $ref: '#/components/schemas/WindowSize' - example: MINUTE - eventType: + - $ref: '#/components/schemas/EntitlementMetered' + title: Entitlement + readOnly: true + feature: + allOf: + - $ref: '#/components/schemas/Feature' + title: Feature + readOnly: true + subject: + allOf: + - $ref: '#/components/schemas/Subject' + title: Subject + readOnly: true + value: + allOf: + - $ref: '#/components/schemas/EntitlementValue' + title: Entitlement Value + readOnly: true + threshold: + allOf: + - $ref: '#/components/schemas/NotificationRuleBalanceThresholdValue' + title: Threshold + readOnly: true + description: Data of the payload for notification event with `entitlements.balance.threshold` type. + NotificationEventDeliveryStatus: + type: object + required: + - state + - reason + - updatedAt + - channel + properties: + state: + allOf: + - $ref: '#/components/schemas/NotificationEventDeliveryStatusState' + example: SUCCESS + description: Delivery state of the notification event to the channel. + readOnly: true + reason: type: string - example: prompt - minLength: 1 - description: The event type to aggregate. - valueProperty: + example: Failed to dispatch event due to provider error. + description: The reason of the last deliverry state update. + title: State Reason + readOnly: true + updatedAt: type: string - example: $.tokens - minLength: 1 - description: |- - JSONPath expression to extract the value from the ingested event's data property. - - The ingested value for SUM, AVG, MIN, and MAX aggregations is a number or a string that can be parsed to a number. - - For UNIQUE_COUNT aggregation, the ingested value must be a string. For COUNT aggregation the valueProperty is ignored. - groupBy: - type: object - additionalProperties: - type: string - example: - type: $.type - description: |- - Named JSONPath expressions to extract the group by values from the event data. - - Keys must be unique and consist only alphanumeric and underscore characters. - - TODO: add key format enforcement - example: - id: 01G65Z755AFWAKHE12NY0CQ9FH - slug: tokens_total - description: AI Token Usage - aggregation: SUM - windowSize: MINUTE - eventType: prompt - valueProperty: $.tokens - groupBy: - model: $.model - type: $.type - description: A meter is a configuration that defines how to match and aggregate events. - x-go-type-import: - path: github.com/openmeterio/openmeter/pkg/models - x-go-type: models.Meter - MeterAggregation: + format: date-time + example: 2023-01-01T01:01:01.001Z + description: Timestamp of when the status was last updated in RFC 3339 format. + title: Last Update Time + readOnly: true + channel: + allOf: + - $ref: '#/components/schemas/NotificationChannelMeta' + description: Notification channel the delivery sattus associated with. + title: Notification Channel + readOnly: true + description: The delivery status of the notification event. + NotificationEventDeliveryStatusState: + type: string + enum: + - SUCCESS + - FAILED + - SENDING + - PENDING + description: The delivery state of the notification event to the channel. + title: Delivery State + x-enum-varnames: + - Success + - Failed + - Sending + - Pending + NotificationEventOrderBy: type: string enum: - - SUM - - COUNT - - UNIQUE_COUNT - - AVG - - MIN - - MAX - description: The aggregation type to use for the meter. - x-go-type-import: - path: github.com/openmeterio/openmeter/pkg/models - x-go-type: models.MeterAggregation - MeterQueryResult: + - id + - createdAt + description: Order by options for notification channels. + NotificationEventPaginatedResponse: type: object required: - - data + - totalCount + - page + - pageSize + - items properties: - from: + totalCount: + type: integer + example: 500 + description: The items in the current page. + page: + type: integer + example: 1 + description: The items in the current page. + pageSize: + type: integer + example: 100 + description: The items in the current page. + items: + type: array + items: + $ref: '#/components/schemas/NotificationEvent' + description: The items in the current page. + description: Paginated response + NotificationEventPayload: + type: object + allOf: + - $ref: '#/components/schemas/NotificationEventBalanceThresholdPayload' + description: The delivery status of the notification event. + NotificationEventType: + type: string + enum: + - entitlements.balance.threshold + description: Type of the notification event. + NotificationRule: + type: object + allOf: + - $ref: '#/components/schemas/NotificationRuleBalanceThreshold' + description: Notification Rule. + NotificationRuleBalanceThreshold: + type: object + required: + - createdAt + - updatedAt + - id + - type + - name + - channels + - thresholds + properties: + createdAt: type: string format: date-time - example: 2023-01-01T01:01:01.001Z - description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' - to: + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was created. + title: Creation Time + readOnly: true + updatedAt: type: string format: date-time - example: 2023-01-01T01:01:01.001Z - description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' - windowSize: - $ref: '#/components/schemas/WindowSize' - data: + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was last updated. + title: Last Update Time + readOnly: true + deletedAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was permanently deleted. + title: Deletion Time + readOnly: true + id: + type: string + example: 01ARZ3NDEKTSV4RRFFQ69G5FAV + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: Identifies the notification rule. + title: Rule Unique Identifier + readOnly: true + type: + type: string + enum: + - entitlements.balance.threshold + description: Notification rule type. + title: Rule Type + name: + type: string + example: Balance threshold reached + description: The user friendly name of the notification rule. + title: Rule Name + disabled: + type: boolean + example: true + description: Whether the rule is disabled or not. + title: Rule Disabled + default: false + channels: type: array items: - $ref: '#/components/schemas/MeterQueryRow' - example: - from: 2023-01-01T00:00:00Z - to: 2023-01-02T00:00:00Z - windowSize: DAY - data: - - value: 12 - windowStart: 2023-01-01T00:00:00Z - windowEnd: 2023-01-02T00:00:00Z - subject: customer-1 - groupBy: - model: gpt-4-turbo - type: prompt - description: The result of a meter query. - MeterQueryRow: + $ref: '#/components/schemas/NotificationChannelMeta' + description: List of notification channels the rule applies to. + title: Channels assigned to Rule + thresholds: + type: array + items: + $ref: '#/components/schemas/NotificationRuleBalanceThresholdValue' + minItems: 1 + maxItems: 10 + description: List of thresholds the rule suppose to be triggered. + title: Entitlement Balance Thresholds + features: + type: array + items: + $ref: '#/components/schemas/FeatureMeta' + minItems: 1 + description: Optional field containing list of features the rule applies to. + title: Features + description: Notification rule with entitlements.balance.threshold type. + NotificationRuleBalanceThresholdCreateRequest: type: object required: - - value - - windowStart - - windowEnd + - type + - name + - thresholds + - channels properties: - value: - type: number - windowStart: - type: string - format: date-time - example: 2023-01-01T01:01:01.001Z - description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' - windowEnd: + type: type: string - format: date-time - example: 2023-01-01T01:01:01.001Z - description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' - subject: + enum: + - entitlements.balance.threshold + description: Notification rule type. + title: Rule Type + name: type: string - groupBy: - type: object - additionalProperties: + example: Balance threshold reached + description: The user friendly name of the notification rule. + title: Rule Name + disabled: + type: boolean + example: true + description: Whether the rule is disabled or not. + title: Rule Disabled + default: false + thresholds: + type: array + items: + $ref: '#/components/schemas/NotificationRuleBalanceThresholdValue' + minItems: 1 + maxItems: 10 + description: List of thresholds the rule suppose to be triggered. + title: Entitlement Balance Thresholds + channels: + type: array + items: type: string - example: - value: 12 - windowStart: 2023-01-01T00:00:00Z - windowEnd: 2023-01-02T00:00:00Z - subject: customer-1 - groupBy: - model: gpt-4-turbo - type: prompt - description: A row in the result of a meter query. - x-go-type-import: - path: github.com/openmeterio/openmeter/pkg/models - x-go-type: models.MeterQueryRow - NotFoundProblemResponse: - type: object - allOf: - - $ref: '#/components/schemas/UnexpectedProblemResponse' - description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. - NotImplementedProblemResponse: - type: object - allOf: - - $ref: '#/components/schemas/UnexpectedProblemResponse' - description: The server does not support the functionality required to fulfill the request. - NotificationChannel: - type: object - allOf: - - $ref: '#/components/schemas/NotificationChannelWebhook' - description: Notification channel. - NotificationChannelCreateRequest: - type: object - allOf: - - $ref: '#/components/schemas/NotificationChannelWebhookCreateRequest' - description: Union type for requests creating new notification channel with certain type. - NotificationChannelMeta: + example: 01G65Z755AFWAKHE12NY0CQ9FH + pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: ULID (Universally Unique Lexicographically Sortable Identifier). + minItems: 1 + description: List of notification channels the rule is applied to. + title: Channels + features: + type: array + items: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$|^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ + description: |- + ULID (Universally Unique Lexicographically Sortable Identifier). + A key is a unique string that is used to identify a resource. + + TODO: this is a temporary solution to support both ULID and Key in the same spec for codegen. + minItems: 1 + description: Optional field for defining the scope of notification by feature. It may contain features by id or key. + title: Features + description: Request with input parameters for creating new notification rule with entitlements.balance.threashold type. + NotificationRuleBalanceThresholdValue: type: object required: - - id + - value - type properties: - id: - type: string - example: 01ARZ3NDEKTSV4RRFFQ69G5FAV - pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: Identifies the notification channel. - title: Channel Unique Identifier - readOnly: true + value: + type: number + format: double + example: 100 + description: Value of the threshold. + title: Threshold Value type: allOf: - - $ref: '#/components/schemas/NotificationChannelType' - description: Notification channel type. - title: Channel Type - readOnly: true - description: Metadata only fields of a notification channel. - NotificationChannelOrderBy: + - $ref: '#/components/schemas/NotificationRuleBalanceThresholdValueType' + example: NUMBER + description: Type of the threshold. + description: Threshold value with multiple supported types. + NotificationRuleBalanceThresholdValueType: + type: string + enum: + - PERCENT + - NUMBER + description: Type of the rule in the balance threshold specification. + title: Notification balance threshold type + x-enum-varnames: + - Percent + - Number + NotificationRuleCreateRequest: + type: object + allOf: + - $ref: '#/components/schemas/NotificationRuleBalanceThresholdCreateRequest' + description: Union type for requests creating new notification rule with certain type. + NotificationRuleOrderBy: type: string enum: - id @@ -9688,7 +11170,7 @@ components: - createdAt - updatedAt description: Order by options for notification channels. - NotificationChannelPaginatedResponse: + NotificationRulePaginatedResponse: type: object required: - totalCount @@ -9711,319 +11193,273 @@ components: items: type: array items: - $ref: '#/components/schemas/NotificationChannel' + $ref: '#/components/schemas/NotificationRule' description: The items in the current page. description: Paginated response - NotificationChannelType: + Numeric: + type: string + pattern: ^\-?[0-9]+(\.[0-9]+)?$ + description: Numeric represents an arbitrary precision number. + x-go-type-import: + path: github.com/alpacahq/alpacadecimal + x-go-type: alpacadecimal.Decimal + OAuth2AuthorizationCodeGrantErrorType: type: string enum: - - WEBHOOK - description: Type of the notification channel. - x-enum-varnames: - - Webhook - NotificationChannelWebhook: - type: object - required: - - createdAt - - updatedAt - - id - - type - - name - - url - properties: - createdAt: - type: string - format: date-time - example: 2024-01-01T01:01:01.001Z - description: Timestamp of when the resource was created. - title: Creation Time - readOnly: true - updatedAt: - type: string - format: date-time - example: 2024-01-01T01:01:01.001Z - description: Timestamp of when the resource was last updated. - title: Last Update Time - readOnly: true - deletedAt: - type: string - format: date-time - example: 2024-01-01T01:01:01.001Z - description: Timestamp of when the resource was permanently deleted. - title: Deletion Time - readOnly: true - id: - type: string - example: 01ARZ3NDEKTSV4RRFFQ69G5FAV - pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: Identifies the notification channel. - title: Channel Unique Identifier - readOnly: true - type: - type: string - enum: - - WEBHOOK - description: Notification channel type. - title: Channel Type - name: - type: string - example: customer-webhook - description: User friendly name of the channel. - title: Channel Name - disabled: - type: boolean - example: true - description: Whether the channel is disabled or not. - title: Channel Disabled - default: false - url: - type: string - example: https://example.com/webhook - description: Webhook URL where the notification is sent. - title: Webhook URL - customHeaders: - type: object - additionalProperties: - type: string - description: Custom HTTP headers sent as part of the webhook request. - title: Custom HTTP Headers - signingSecret: - type: string - example: whsec_S6g2HLnTwd9AhHwUIMFggVS9OfoPafN8 - pattern: ^(whsec_)?[a-zA-Z0-9+/=]{32,100}$ - description: |- - Signing secret used for webhook request validation on the receiving end. - - Format: `base64` encoded random bytes optionally prefixed with `whsec_`. Recommended size: 24 - title: Signing Secret - description: Notification channel with webhook type. - NotificationChannelWebhookCreateRequest: - type: object - required: - - type - - name - - url - properties: - type: - type: string - enum: - - WEBHOOK - description: Notification channel type. - title: Channel Type - name: - type: string - example: customer-webhook - description: User friendly name of the channel. - title: Channel Name - disabled: - type: boolean - example: true - description: Whether the channel is disabled or not. - title: Channel Disabled - default: false - url: - type: string - example: https://example.com/webhook - description: Webhook URL where the notification is sent. - title: Webhook URL - customHeaders: - type: object - additionalProperties: - type: string - description: Custom HTTP headers sent as part of the webhook request. - title: Custom HTTP Headers - signingSecret: - type: string - example: whsec_S6g2HLnTwd9AhHwUIMFggVS9OfoPafN8 - pattern: ^(whsec_)?[a-zA-Z0-9+/=]{32,100}$ - description: |- - Signing secret used for webhook request validation on the receiving end. - - Format: `base64` encoded random bytes optionally prefixed with `whsec_`. Recommended size: 24 - title: Signing Secret - description: Request with input parameters for creating new notification channel with webhook type. - NotificationEvent: + - invalid_request + - unauthorized_client + - access_denied + - unsupported_response_type + - invalid_scope + - server_error + - temporarily_unavailable + description: OAuth2 authorization code grant error types. + OpenMeter.App.Type: + type: string + enum: + - stripe + description: Type of the app. + Percentage: + type: string + pattern: ^\-?[0-9]+(\.[0-9]+)?%$ + description: Numeric representation of a percentage + x-go-type-import: + path: github.com/alpacahq/alpacadecimal + x-go-type: alpacadecimal.Decimal + Period: type: object - required: - - id - - type - - createdAt - - rule - - deliveryStatus - - payload - properties: - id: - type: string - example: 01J2KNP1YTXQRXHTDJ4KPR7PZ0 - pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: A unique identifier of the notification event. - title: Event Identifier - readOnly: true - type: - allOf: - - $ref: '#/components/schemas/NotificationEventType' - description: Type of the notification event. - title: Event Type - readOnly: true - createdAt: - type: string - format: date-time - example: 2023-01-01T01:01:01.001Z - description: Timestamp when the notification event was created in RFC 3339 format. - title: Creation Time - readOnly: true - rule: - allOf: - - $ref: '#/components/schemas/NotificationRule' - description: The nnotification rule which generated this event. - title: Owner Rule - readOnly: true - deliveryStatus: - type: array - items: - $ref: '#/components/schemas/NotificationEventDeliveryStatus' - description: The delivery status of the notification event. - title: Delivery Status - readOnly: true - payload: - allOf: - - $ref: '#/components/schemas/NotificationEventPayload' - description: Timestamp when the notification event was created in RFC 3339 format. - title: Event Payload - readOnly: true - annotations: - allOf: - - $ref: '#/components/schemas/Annotations' - description: Set of key-value pairs managed by the system. Cannot be modified by user. - title: Annotations - readOnly: true - description: Type of the notification event. - NotificationEventBalanceThresholdPayload: + required: + - from + - to + properties: + from: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: Period start time. + to: + type: string + format: date-time + example: 2023-02-01T01:01:01.001Z + description: Period end time. + description: A period with a start and end time. + PhasesOrderBy: + type: string + enum: + - key + description: Order by options for plan phases. + Plan: type: object required: - id - - type - - timestamp - - data + - name + - createdAt + - updatedAt + - key + - version + - currency + - status + - phases properties: id: type: string - example: 01J2KNP1YTXQRXHTDJ4KPR7PZ0 + example: 01G65Z755AFWAKHE12NY0CQ9FH pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: A unique identifier for the notification event the payload belongs to. - title: Notification Event Identifier + description: A unique identifier for the resource. + title: ID readOnly: true - type: + name: type: string - enum: - - entitlements.balance.threshold - description: Type of the notification event. - title: Notification Event Type - readOnly: true - timestamp: + minLength: 1 + maxLength: 256 + description: Human-readable name for the resource. Between 1 and 256 characters. + title: Display name + description: + type: string + maxLength: 1024 + description: Optional description of the resource. Maximum 1024 characters. + title: Description + metadata: + allOf: + - $ref: '#/components/schemas/Metadata' + description: Additional metadata for the resource. + title: Metadata + createdAt: type: string format: date-time - example: 2023-01-01T01:01:01.001Z - description: Timestamp when the notification event was created in RFC 3339 format. + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was created. title: Creation Time readOnly: true - data: - allOf: - - $ref: '#/components/schemas/NotificationEventBalanceThresholdPayloadData' - description: The data of the payload. - title: Payload Data - readOnly: true - description: Payload for notification event with `entitlements.balance.threshold` type. - NotificationEventBalanceThresholdPayloadData: - type: object - required: - - entitlement - - feature - - subject - - value - - threshold - properties: - entitlement: - allOf: - - $ref: '#/components/schemas/EntitlementMetered' - title: Entitlement + updatedAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was last updated. + title: Last Update Time readOnly: true - feature: - allOf: - - $ref: '#/components/schemas/Feature' - title: Feature + deletedAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was permanently deleted. + title: Deletion Time readOnly: true - subject: - allOf: - - $ref: '#/components/schemas/Subject' - title: Subject + key: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A semi-unique identifier for the resource. + title: Key + version: + type: integer + minimum: 1 + description: Version of the plan. Incremented when the plan is updated. + title: Version + default: 1 readOnly: true - value: + currency: allOf: - - $ref: '#/components/schemas/EntitlementValue' - title: Entitlement Value - readOnly: true - threshold: + - $ref: '#/components/schemas/CurrencyCode' + description: The currency code of the plan. + title: Currency + default: USD + effectiveFrom: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: The date and time when the plan becomes effective. When not specified, the plan is a draft. + title: Effective start date + effectiveTo: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: The date and time when the plan is no longer effective. When not specified, the plan is effective indefinitely. + title: Effective end date + status: allOf: - - $ref: '#/components/schemas/NotificationRuleBalanceThresholdValue' - title: Threshold + - $ref: '#/components/schemas/PlanStatus' + description: |- + The status of the plan. + Computed based on the effective start and end dates: + - draft = no effectiveStartDate + - active = effectiveStartDate <= now < effectiveEndDate + - archived / inactive = effectiveEndDate <= now + title: Status readOnly: true - description: Data of the payload for notification event with `entitlements.balance.threshold` type. - NotificationEventDeliveryStatus: + phases: + type: array + items: + $ref: '#/components/schemas/PlanPhase' + minItems: 1 + description: |- + The plan phase or pricing ramp allows changing a plan's rate cards over time as a subscription progresses. + A phase switch occurs only at the end of a billing period, ensuring that a single subscription invoice will not include charges from different phase prices. + title: Plan phases + description: Plans provide a template for subscriptions. + PlanCreate: type: object required: - - state - - reason - - updatedAt - - channel + - name + - key + - currency + - phases properties: - state: + name: + type: string + minLength: 1 + maxLength: 256 + description: Human-readable name for the resource. Between 1 and 256 characters. + title: Display name + description: + type: string + maxLength: 1024 + description: Optional description of the resource. Maximum 1024 characters. + title: Description + metadata: allOf: - - $ref: '#/components/schemas/NotificationEventDeliveryStatusState' - example: SUCCESS - description: Delivery state of the notification event to the channel. - readOnly: true - reason: + - $ref: '#/components/schemas/Metadata' + description: Additional metadata for the resource. + title: Metadata + key: type: string - example: Failed to dispatch event due to provider error. - description: The reason of the last deliverry state update. - title: State Reason - readOnly: true - updatedAt: + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A semi-unique identifier for the resource. + title: Key + currency: + allOf: + - $ref: '#/components/schemas/CurrencyCode' + description: The currency code of the plan. + title: Currency + default: USD + effectiveFrom: type: string format: date-time example: 2023-01-01T01:01:01.001Z - description: Timestamp of when the status was last updated in RFC 3339 format. - title: Last Update Time - readOnly: true - channel: - allOf: - - $ref: '#/components/schemas/NotificationChannelMeta' - description: Notification channel the delivery sattus associated with. - title: Notification Channel - readOnly: true - description: The delivery status of the notification event. - NotificationEventDeliveryStatusState: - type: string - enum: - - SUCCESS - - FAILED - - SENDING - - PENDING - description: The delivery state of the notification event to the channel. - title: Delivery State - x-enum-varnames: - - Success - - Failed - - Sending - - Pending - NotificationEventOrderBy: + description: The date and time when the plan becomes effective. When not specified, the plan is a draft. + title: Effective start date + effectiveTo: + type: string + format: date-time + example: 2023-01-01T01:01:01.001Z + description: The date and time when the plan is no longer effective. When not specified, the plan is effective indefinitely. + title: Effective end date + phases: + type: array + items: + $ref: '#/components/schemas/PlanPhase' + minItems: 1 + description: |- + The plan phase or pricing ramp allows changing a plan's rate cards over time as a subscription progresses. + A phase switch occurs only at the end of a billing period, ensuring that a single subscription invoice will not include charges from different phase prices. + title: Plan phases + description: Resource create operation model. + PlanDiscount: + type: object + allOf: + - $ref: '#/components/schemas/PlanDiscountPercentage' + description: 'A discount on plan. One of: percentage or amount.' + PlanDiscountPercentage: + type: object + required: + - type + - percentage + properties: + type: + type: string + enum: + - percentage + description: The type of the discount. + title: Type + percentage: + type: number + minimum: 0 + maximum: 100 + description: The percentage of the discount. + title: Percentage + appliesToRateCards: + type: array + items: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A key is a unique string that is used to identify a resource. + description: |- + The rate cards that the discount applies to. + When not specified, the discount applies to all rate cards. + title: Applies To + description: Percentage discount on plan. + PlanOrderBy: type: string enum: - id - - createdAt - description: Order by options for notification channels. - NotificationEventPaginatedResponse: + - key + description: Order by options for plans. + PlanPaginatedResponse: type: object required: - totalCount @@ -10044,37 +11480,37 @@ components: example: 100 description: The items in the current page. items: - type: array - items: - $ref: '#/components/schemas/NotificationEvent' - description: The items in the current page. - description: Paginated response - NotificationEventPayload: - type: object - allOf: - - $ref: '#/components/schemas/NotificationEventBalanceThresholdPayload' - description: The delivery status of the notification event. - NotificationEventType: - type: string - enum: - - entitlements.balance.threshold - description: Type of the notification event. - NotificationRule: - type: object - allOf: - - $ref: '#/components/schemas/NotificationRuleBalanceThreshold' - description: Notification Rule. - NotificationRuleBalanceThreshold: + type: array + items: + $ref: '#/components/schemas/Plan' + description: The items in the current page. + description: Paginated response + PlanPhase: type: object required: + - name - createdAt - updatedAt - - id - - type - - name - - channels - - thresholds + - key + - interval + - rateCards properties: + name: + type: string + minLength: 1 + maxLength: 256 + description: Human-readable name for the resource. Between 1 and 256 characters. + title: Display name + description: + type: string + maxLength: 1024 + description: Optional description of the resource. Maximum 1024 characters. + title: Description + metadata: + allOf: + - $ref: '#/components/schemas/Metadata' + description: Additional metadata for the resource. + title: Metadata createdAt: type: string format: date-time @@ -10096,153 +11532,87 @@ components: description: Timestamp of when the resource was permanently deleted. title: Deletion Time readOnly: true - id: - type: string - example: 01ARZ3NDEKTSV4RRFFQ69G5FAV - pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: Identifies the notification rule. - title: Rule Unique Identifier - readOnly: true - type: + key: type: string - enum: - - entitlements.balance.threshold - description: Notification rule type. - title: Rule Type - name: + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A semi-unique identifier for the resource. + title: Key + interval: type: string - example: Balance threshold reached - description: The user friendly name of the notification rule. - title: Rule Name - disabled: - type: boolean - example: true - description: Whether the rule is disabled or not. - title: Rule Disabled - default: false - channels: - type: array - items: - $ref: '#/components/schemas/NotificationChannelMeta' - description: List of notification channels the rule applies to. - title: Channels assigned to Rule - thresholds: - type: array - items: - $ref: '#/components/schemas/NotificationRuleBalanceThresholdValue' - minItems: 1 - maxItems: 10 - description: List of thresholds the rule suppose to be triggered. - title: Entitlement Balance Thresholds - features: + format: duration + nullable: true + example: P1Y1D + description: |- + Interval after the subscription starts to transition to the phase. + When null, the phase starts immediately after the subscription starts. + title: Interval + rateCards: type: array items: - $ref: '#/components/schemas/FeatureMeta' - minItems: 1 - description: Optional field containing list of features the rule applies to. - title: Features - description: Notification rule with entitlements.balance.threshold type. - NotificationRuleBalanceThresholdCreateRequest: + $ref: '#/components/schemas/RateCard' + description: The rate cards of the plan. + title: Rate cards + discount: + allOf: + - $ref: '#/components/schemas/PlanDiscount' + description: The discount on the plan. + title: Discount + description: The plan phase or pricing ramp allows changing a plan's rate cards over time as a subscription progresses. + PlanPhaseCreate: type: object required: - - type - name - - thresholds - - channels + - key + - interval + - rateCards properties: - type: - type: string - enum: - - entitlements.balance.threshold - description: Notification rule type. - title: Rule Type name: type: string - example: Balance threshold reached - description: The user friendly name of the notification rule. - title: Rule Name - disabled: - type: boolean - example: true - description: Whether the rule is disabled or not. - title: Rule Disabled - default: false - thresholds: - type: array - items: - $ref: '#/components/schemas/NotificationRuleBalanceThresholdValue' - minItems: 1 - maxItems: 10 - description: List of thresholds the rule suppose to be triggered. - title: Entitlement Balance Thresholds - channels: - type: array - items: - type: string - example: 01G65Z755AFWAKHE12NY0CQ9FH - pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: ULID (Universally Unique Lexicographically Sortable Identifier). - minItems: 1 - description: List of notification channels the rule is applied to. - title: Channels - features: + minLength: 1 + maxLength: 256 + description: Human-readable name for the resource. Between 1 and 256 characters. + title: Display name + description: + type: string + maxLength: 1024 + description: Optional description of the resource. Maximum 1024 characters. + title: Description + metadata: + allOf: + - $ref: '#/components/schemas/Metadata' + description: Additional metadata for the resource. + title: Metadata + key: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A semi-unique identifier for the resource. + title: Key + interval: + type: string + format: duration + nullable: true + example: P1Y1D + description: |- + Interval after the subscription starts to transition to the phase. + When null, the phase starts immediately after the subscription starts. + title: Interval + rateCards: type: array items: - type: string - minLength: 1 - maxLength: 64 - pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$|^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: |- - ULID (Universally Unique Lexicographically Sortable Identifier). - A key is a unique string that is used to identify a resource. - - TODO: this is a temporary solution to support both ULID and Key in the same spec for codegen. - minItems: 1 - description: Optional field for defining the scope of notification by feature. It may contain features by id or key. - title: Features - description: Request with input parameters for creating new notification rule with entitlements.balance.threashold type. - NotificationRuleBalanceThresholdValue: - type: object - required: - - value - - type - properties: - value: - type: number - format: double - example: 100 - description: Value of the threshold. - title: Threshold Value - type: + $ref: '#/components/schemas/RateCard' + description: The rate cards of the plan. + title: Rate cards + discount: allOf: - - $ref: '#/components/schemas/NotificationRuleBalanceThresholdValueType' - example: NUMBER - description: Type of the threshold. - description: Threshold value with multiple supported types. - NotificationRuleBalanceThresholdValueType: - type: string - enum: - - PERCENT - - NUMBER - description: Type of the rule in the balance threshold specification. - title: Notification balance threshold type - x-enum-varnames: - - Percent - - Number - NotificationRuleCreateRequest: - type: object - allOf: - - $ref: '#/components/schemas/NotificationRuleBalanceThresholdCreateRequest' - description: Union type for requests creating new notification rule with certain type. - NotificationRuleOrderBy: - type: string - enum: - - id - - type - - createdAt - - updatedAt - description: Order by options for notification channels. - NotificationRulePaginatedResponse: + - $ref: '#/components/schemas/PlanDiscount' + description: The discount on the plan. + title: Discount + description: Resource create operation model. + PlanPhasePaginatedResponse: type: object required: - totalCount @@ -10265,56 +11635,103 @@ components: items: type: array items: - $ref: '#/components/schemas/NotificationRule' + $ref: '#/components/schemas/PlanPhase' description: The items in the current page. description: Paginated response - Numeric: - type: string - pattern: ^\-?[0-9]+(\.[0-9]+)?$ - description: Numeric represents an arbitrary precision number. - x-go-type-import: - path: github.com/alpacahq/alpacadecimal - x-go-type: alpacadecimal.Decimal - OAuth2AuthorizationCodeGrantErrorType: - type: string - enum: - - invalid_request - - unauthorized_client - - access_denied - - unsupported_response_type - - invalid_scope - - server_error - - temporarily_unavailable - description: OAuth2 authorization code grant error types. - OpenMeter.App.Type: - type: string - enum: - - stripe - description: Type of the app. - Percentage: + PlanPhaseUpdate: + type: object + properties: + name: + type: string + minLength: 1 + maxLength: 256 + description: Human-readable name for the resource. Between 1 and 256 characters. + title: Display name + description: + type: string + maxLength: 1024 + description: Optional description of the resource. Maximum 1024 characters. + title: Description + metadata: + allOf: + - $ref: '#/components/schemas/Metadata' + description: Additional metadata for the resource. + title: Metadata + interval: + type: string + format: duration + nullable: true + example: P1Y1D + description: |- + Interval after the subscription starts to transition to the phase. + When null, the phase starts immediately after the subscription starts. + title: Interval + rateCards: + type: array + items: + $ref: '#/components/schemas/RateCard' + description: The rate cards of the plan. + title: Rate cards + discount: + allOf: + - $ref: '#/components/schemas/PlanDiscount' + description: The discount on the plan. + title: Discount + description: Resource create or update operation model. + PlanStatus: type: string - pattern: ^\-?[0-9]+(\.[0-9]+)?%$ - description: Numeric representation of a percentage - x-go-type-import: - path: github.com/alpacahq/alpacadecimal - x-go-type: alpacadecimal.Decimal - Period: + enum: + - draft + - active + - archived + description: The status of a plan. + PlanUpdate: type: object - required: - - from - - to properties: - from: + name: + type: string + minLength: 1 + maxLength: 256 + description: Human-readable name for the resource. Between 1 and 256 characters. + title: Display name + description: + type: string + maxLength: 1024 + description: Optional description of the resource. Maximum 1024 characters. + title: Description + metadata: + allOf: + - $ref: '#/components/schemas/Metadata' + description: Additional metadata for the resource. + title: Metadata + currency: + allOf: + - $ref: '#/components/schemas/CurrencyCode' + description: The currency code of the plan. + title: Currency + default: USD + effectiveFrom: type: string format: date-time example: 2023-01-01T01:01:01.001Z - description: Period start time. - to: + description: The date and time when the plan becomes effective. When not specified, the plan is a draft. + title: Effective start date + effectiveTo: type: string format: date-time - example: 2023-02-01T01:01:01.001Z - description: Period end time. - description: A period with a start and end time. + example: 2023-01-01T01:01:01.001Z + description: The date and time when the plan is no longer effective. When not specified, the plan is effective indefinitely. + title: Effective end date + phases: + type: array + items: + $ref: '#/components/schemas/PlanPhase' + minItems: 1 + description: |- + The plan phase or pricing ramp allows changing a plan's rate cards over time as a subscription progresses. + A phase switch occurs only at the end of a billing period, ensuring that a single subscription invoice will not include charges from different phase prices. + title: Plan phases + description: Resource create or update operation model. PortalToken: type: object required: @@ -10433,7 +11850,7 @@ components: description: The items in the current page. description: Paginated response RateCard: - anyOf: + oneOf: - $ref: '#/components/schemas/RateCardFlatFee' - $ref: '#/components/schemas/RateCardUsageBased' discriminator: @@ -10442,22 +11859,45 @@ components: flat_fee: '#/components/schemas/RateCardFlatFee' usage_based: '#/components/schemas/RateCardUsageBased' description: A rate card defines the pricing and entitlement of a feature or service. - RateCardBase: + RateCardBooleanEntitlement: + type: object + required: + - type + properties: + metadata: + allOf: + - $ref: '#/components/schemas/Metadata' + description: Additional metadata for the feature. + type: + type: string + enum: + - boolean + description: Entitlement template of a boolean entitlement. + RateCardEntitlement: + anyOf: + - $ref: '#/components/schemas/RateCardMeteredEntitlement' + - $ref: '#/components/schemas/RateCardStaticEntitlement' + - $ref: '#/components/schemas/RateCardBooleanEntitlement' + discriminator: + propertyName: type + mapping: + metered: '#/components/schemas/RateCardMeteredEntitlement' + static: '#/components/schemas/RateCardStaticEntitlement' + boolean: '#/components/schemas/RateCardBooleanEntitlement' + description: |- + Entitlement templates are used to define the entitlements of a plan. + Features are omitted from the entitlement template, as they are defined in the rate card. + RateCardFlatFee: type: object required: - - id - name - createdAt - updatedAt + - key - type + - billingCandence + - price properties: - id: - type: string - example: 01G65Z755AFWAKHE12NY0CQ9FH - pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$ - description: A unique identifier for the resource. - title: ID - readOnly: true name: type: string minLength: 1 @@ -10495,11 +11935,19 @@ components: description: Timestamp of when the resource was permanently deleted. title: Deletion Time readOnly: true + key: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A semi-unique identifier for the resource. + title: Key type: - allOf: - - $ref: '#/components/schemas/RateCardType' - description: The type of the rate card - title: Type of the rate card + type: string + enum: + - flat_fee + description: The type of the RateCard. + title: Channel Type featureKey: type: string minLength: 1 @@ -10521,46 +11969,6 @@ components: The tax config of the rate card. When undefined, the tax config of the feature or the default tax config of the plan is used. title: Tax config - description: Common fields of the rate card. - RateCardBooleanEntitlement: - type: object - required: - - type - properties: - metadata: - allOf: - - $ref: '#/components/schemas/Metadata' - description: Additional metadata for the feature. - type: - type: string - enum: - - boolean - description: Entitlement template of a boolean entitlement. - RateCardEntitlement: - anyOf: - - $ref: '#/components/schemas/RateCardMeteredEntitlement' - - $ref: '#/components/schemas/RateCardStaticEntitlement' - - $ref: '#/components/schemas/RateCardBooleanEntitlement' - discriminator: - propertyName: type - mapping: - metered: '#/components/schemas/RateCardMeteredEntitlement' - static: '#/components/schemas/RateCardStaticEntitlement' - boolean: '#/components/schemas/RateCardBooleanEntitlement' - description: |- - Entitlement templates are used to define the entitlements of a plan. - Features are omitted from the entitlement template, as they are defined in the rate card. - RateCardFlatFee: - type: object - required: - - type - - billingCandence - - price - properties: - type: - type: string - enum: - - flat_fee billingCandence: type: string format: duration @@ -10579,16 +11987,6 @@ components: The price of the rate card. When null, the feature or service is free. title: Price - discount: - anyOf: - - $ref: '#/components/schemas/DiscountPercentage' - - $ref: '#/components/schemas/DiscountAmount' - description: |- - The discount of the rate card. Either a percentage or an amount. - Only available when price is set. - title: Discount - allOf: - - $ref: '#/components/schemas/RateCardBase' description: A flat fee rate card defines a one-time purchase or a recurring fee. RateCardMeteredEntitlement: type: object @@ -10659,23 +12057,88 @@ components: example: '{ "integrations": ["github"] }' description: The JSON parsable config of the entitlement. This value is also returned when checking entitlement access and it is useful for configuring fine-grained access settings to the feature, implemented in your own system. Has to be an object. description: Entitlement template of a static entitlement. - RateCardType: - type: string - enum: - - flat_fee - - usage_based - description: The type of the rate card. RateCardUsageBased: type: object required: + - name + - createdAt + - updatedAt + - key - type - billingCandence - price properties: + name: + type: string + minLength: 1 + maxLength: 256 + description: Human-readable name for the resource. Between 1 and 256 characters. + title: Display name + description: + type: string + maxLength: 1024 + description: Optional description of the resource. Maximum 1024 characters. + title: Description + metadata: + allOf: + - $ref: '#/components/schemas/Metadata' + description: Additional metadata for the resource. + title: Metadata + createdAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was created. + title: Creation Time + readOnly: true + updatedAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was last updated. + title: Last Update Time + readOnly: true + deletedAt: + type: string + format: date-time + example: 2024-01-01T01:01:01.001Z + description: Timestamp of when the resource was permanently deleted. + title: Deletion Time + readOnly: true + key: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: A semi-unique identifier for the resource. + title: Key type: type: string enum: - usage_based + description: The type of the RateCard. + title: Channel Type + featureKey: + type: string + minLength: 1 + maxLength: 64 + pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ + description: The feature the customer is entitled to use. + title: Feature key + entitlementTemplate: + allOf: + - $ref: '#/components/schemas/RateCardEntitlement' + description: |- + The entitlement of the rate card. + Only available when featureKey is set. + title: Entitlement template + taxConfig: + allOf: + - $ref: '#/components/schemas/TaxConfig' + description: |- + The tax config of the rate card. + When undefined, the tax config of the feature or the default tax config of the plan is used. + title: Tax config billingCandence: type: string format: duration @@ -10683,10 +12146,18 @@ components: title: Billing cadence price: anyOf: - - $ref: '#/components/schemas/UnitPriceWithCommitments' - - $ref: '#/components/schemas/TieredPriceWithCommitments' - - $ref: '#/components/schemas/FlatPriceWithPaymentTerm' - nullable: true + - type: object + allOf: + - $ref: '#/components/schemas/UnitPriceWithCommitments' + nullable: true + - type: object + allOf: + - $ref: '#/components/schemas/TieredPriceWithCommitments' + nullable: true + - type: object + allOf: + - $ref: '#/components/schemas/FlatPriceWithPaymentTerm' + nullable: true example: {} description: |- The price of the rate card. @@ -10697,8 +12168,6 @@ components: - $ref: '#/components/schemas/Discount' description: The discount of the rate card. title: Discount - allOf: - - $ref: '#/components/schemas/RateCardBase' description: A usage-based rate card defines a price based on usage. RecurringPeriod: type: object @@ -11120,7 +12589,13 @@ components: description: Stripe tax config. title: Stripe tax config description: A tax config. - TieredPrice: + TieredPriceMode: + type: string + enum: + - volume + - graduated + description: The mode of the tiered price. + TieredPriceWithCommitments: type: object required: - type @@ -11146,16 +12621,6 @@ components: description: |- The tiers of the tiered price. At least one price component is required in each tier. - description: Tiered price. - TieredPriceMode: - type: string - enum: - - volume - - graduated - description: The mode of the tiered price. - TieredPriceWithCommitments: - type: object - properties: minimumAmount: allOf: - $ref: '#/components/schemas/Numeric' @@ -11166,8 +12631,6 @@ components: - $ref: '#/components/schemas/Numeric' description: The customer is limited to spend at most the amount. title: Maximum amount - allOf: - - $ref: '#/components/schemas/TieredPrice' description: Tiered price with spend commitments. UnauthorizedProblemResponse: type: object @@ -11235,7 +12698,18 @@ components: description: Unit price. UnitPriceWithCommitments: type: object + required: + - type + - amount properties: + type: + type: string + enum: + - unit + amount: + allOf: + - $ref: '#/components/schemas/Numeric' + description: The amount of the unit price. minimumAmount: allOf: - $ref: '#/components/schemas/Numeric' @@ -11246,27 +12720,7 @@ components: - $ref: '#/components/schemas/Numeric' description: The customer is limited to spend at most the amount. title: Maximum amount - allOf: - - $ref: '#/components/schemas/UnitPrice' description: Unit price with spend commitments. - UsageDiscount: - type: object - required: - - type - - usage - properties: - type: - type: string - enum: - - usage - description: The type of the discount. - title: Type - usage: - type: number - format: double - description: The usage discount. - title: Usage - description: Usage discount. WindowSize: type: string enum: diff --git a/api/spec/src/billing/invoices/invoice.tsp b/api/spec/src/billing/invoices/invoice.tsp index 113cd554c..cb1b8cd7d 100644 --- a/api/spec/src/billing/invoices/invoice.tsp +++ b/api/spec/src/billing/invoices/invoice.tsp @@ -1,12 +1,13 @@ import "@typespec/http"; import "@typespec/rest"; import "@typespec/openapi3"; -import "../../ratecards.tsp"; using TypeSpec.Http; using TypeSpec.Rest; using TypeSpec.OpenAPI; +using OpenMeter.ProductCatalog; + namespace Invoices; /** @@ -282,7 +283,7 @@ model UnitPriceLine extends Line { type: LineTypes.unitPrice; @summary("Details about what is being sold.") - item: OpenMeter.RateCard; + item: RateCard; @summary("Quantity of the item being sold.") quantity: Numeric; diff --git a/api/spec/src/billing/invoices/main.tsp b/api/spec/src/billing/invoices/main.tsp index 374a381a9..dc165342c 100644 --- a/api/spec/src/billing/invoices/main.tsp +++ b/api/spec/src/billing/invoices/main.tsp @@ -5,6 +5,7 @@ import "@typespec/openapi3"; import "@typespec/versioning"; import "../.."; +import "../../productcatalog"; // Package Contents import "./invoice.tsp"; diff --git a/api/spec/src/cloud/main.tsp b/api/spec/src/cloud/main.tsp index 7c3bd1d52..9604e9721 100644 --- a/api/spec/src/cloud/main.tsp +++ b/api/spec/src/cloud/main.tsp @@ -175,3 +175,25 @@ namespace OpenMeterCloud.Billing { @tag("Billing (Experimental)") interface CustomerInvoiceEndpoints extends OpenMeter.Billing.CustomerInvoiceEndpoints {} } + +namespace OpenMeterCloud.ProductCatalog { + @route("/api/v1/plans") + @tag("Plan (Experimental)") + interface PlansById extends OpenMeter.ProductCatalog.Plans {} + + @route("/api/v1/plans/{planId}/publish") + @tag("Plan (Experimental)") + interface PlanPublishById extends OpenMeter.ProductCatalog.PlanPublish {} + + @route("/api/v1/plans/{planId}/unpublish") + @tag("Plan (Experimental)") + interface PlanUnpublishById extends OpenMeter.ProductCatalog.PlanUnpublish {} + + @route("/api/v1/plans/{planId}/next") + @tag("Plan (Experimental)") + interface PlanNewDraftVersion extends OpenMeter.ProductCatalog.PlanNewDraftVersion {} + + @route("/api/v1/plans/{planId}/phases") + @tag("Plan (Experimental)") + interface PlanByIdPhases extends OpenMeter.ProductCatalog.PlanPhases {} +} diff --git a/api/spec/src/discounts.tsp b/api/spec/src/discounts.tsp deleted file mode 100644 index 2f06c330d..000000000 --- a/api/spec/src/discounts.tsp +++ /dev/null @@ -1,86 +0,0 @@ -import "./types.tsp"; - -namespace OpenMeter; - -/** - * The type of the discount. - */ -@friendlyName("DiscountType") -enum DiscountType { - percentage: "percentage", - amount: "amount", - usage: "usage", -} - -/** - * A discount on a price. - * One of: percentage, amount, or usage. - */ -@discriminator("type") -@friendlyName("Discount") -union Discount { - @summary("Percentage discount") - percentage: DiscountPercentage, - - @summary("Amount discount") - amount: DiscountAmount, - - @summary("Usage discount") - usage: DiscountUsage, -} - -/** - * Percentage discount. - */ -@friendlyName("DiscountPercentage") -model DiscountPercentage { - /** - * The type of the discount. - */ - @summary("Type") - type: DiscountType.percentage; - - /** - * The percentage of the discount. - */ - @summary("Percentage") - @minValue(0) - @maxValue(100) - percentage: float; -} - -/** - * Amount discount. - */ -@friendlyName("DiscountAmount") -model DiscountAmount { - /** - * The type of the discount. - */ - @summary("Type") - type: DiscountType.amount; - - /** - * The amount of the discount. - */ - @summary("Amount") - amount: Money; -} - -/** - * Usage discount. - */ -@friendlyName("UsageDiscount") -model DiscountUsage { - /** - * The type of the discount. - */ - @summary("Type") - type: DiscountType.usage; - - /** - * The usage discount. - */ - @summary("Usage") - usage: float64; -} diff --git a/api/spec/src/main.tsp b/api/spec/src/main.tsp index e2a8578f8..4264a6b6e 100644 --- a/api/spec/src/main.tsp +++ b/api/spec/src/main.tsp @@ -19,6 +19,7 @@ import "./debug.tsp"; import "./notification"; import "./entitlements"; import "./billing"; +import "./productcatalog"; using TypeSpec.Http; using TypeSpec.Rest; diff --git a/api/spec/src/productcatalog/discounts.tsp b/api/spec/src/productcatalog/discounts.tsp new file mode 100644 index 000000000..9bafedd0f --- /dev/null +++ b/api/spec/src/productcatalog/discounts.tsp @@ -0,0 +1,86 @@ +namespace OpenMeter.ProductCatalog; + +/** + * The type of the discount. + */ +@friendlyName("DiscountType") +enum DiscountType { + percentage: "percentage", + amount: "amount", + usage: "usage", +} + +/** + * A discount on a price. + * One of: percentage, amount, or usage. + */ +@discriminator("type") +@friendlyName("Discount") +union Discount { + @summary("Percentage discount") + percentage: DiscountPercentage, + + // @summary("Amount discount") + // amount: DiscountAmount, + + // @summary("Usage discount") + // usage: DiscountUsage, +} + +/** + * Percentage discount. + */ +@friendlyName("DiscountPercentage") +model DiscountPercentage { + /** + * The type of the discount. + */ + @summary("Type") + type: DiscountType.percentage; + + /** + * The percentage of the discount. + */ + @summary("Percentage") + @minValue(0) + @maxValue(100) + percentage: float; +} + +// NOTE(chrisgacsal): amount discount is going to be implemented in future releases +// /** +// * Amount discount. +// */ +// @friendlyName("DiscountAmount") +// model DiscountAmount { +// /** +// * The type of the discount. +// */ +// @summary("Type") +// type: DiscountType.amount; + +// /** +// * The amount of the discount. +// */ +// @summary("Amount") +// amount: Money; +// } + +// NOTE(chrisgacsal): usage discount is going to be implemented in future releases +// /** +// * Usage discount. +// */ +// @friendlyName("UsageDiscount") +// model DiscountUsage { +// /** +// * The type of the discount. +// */ +// @summary("Type") +// type: DiscountType.usage; + +// /** +// * The usage discount. +// */ +// @summary("Usage") +// usage: float64; +// } diff --git a/api/spec/src/productcatalog/main.tsp b/api/spec/src/productcatalog/main.tsp new file mode 100644 index 000000000..43220ca72 --- /dev/null +++ b/api/spec/src/productcatalog/main.tsp @@ -0,0 +1,14 @@ +import "@typespec/http"; +import "@typespec/openapi"; +import "@typespec/openapi3"; + +import ".."; + +// Package Contents +import "./discounts.tsp"; +import "./plan.tsp"; +import "./prices.tsp"; +import "./ratecards.tsp"; +import "./routes.tsp"; + +namespace OpenMeter.ProductCatalog; diff --git a/api/spec/src/plan.tsp b/api/spec/src/productcatalog/plan.tsp similarity index 72% rename from api/spec/src/plan.tsp rename to api/spec/src/productcatalog/plan.tsp index 8481d0026..418b31532 100644 --- a/api/spec/src/plan.tsp +++ b/api/spec/src/productcatalog/plan.tsp @@ -1,14 +1,7 @@ -import "@typespec/http"; -import "./types.tsp"; -import "./ratecards.tsp"; - -namespace OpenMeter; +namespace OpenMeter.ProductCatalog; using TypeSpec.Http; - -@route("/api/v1/plans") -@tag("Plans") -interface Plans {} +using TypeSpec.OpenAPI; /** * The status of a plan. @@ -24,12 +17,15 @@ enum PlanStatus { * Plans provide a template for subscriptions. */ @friendlyName("Plan") -model Plan extends UniqueResource { +model Plan { + ...UniqueResource; + /** * Version of the plan. Incremented when the plan is updated. */ @summary("Version") @minValue(1) + @visibility("read") version: integer = 1; /** @@ -42,13 +38,13 @@ model Plan extends UniqueResource { * The date and time when the plan becomes effective. When not specified, the plan is a draft. */ @summary("Effective start date") - effectiveStartDate?: DateTime; + effectiveFrom?: DateTime; /** * The date and time when the plan is no longer effective. When not specified, the plan is effective indefinitely. */ @summary("Effective end date") - effectiveEndDate?: DateTime; + effectiveTo?: DateTime; /** * The status of the plan. @@ -75,12 +71,16 @@ model Plan extends UniqueResource { */ @friendlyName("PlanPhase") model PlanPhase { + ...OmitProperties; + /** * Interval after the subscription starts to transition to the phase. * When null, the phase starts immediately after the subscription starts. */ - @summary("Start after") - startAfter: Interval | null; + @encode(DurationKnownEncoding.ISO8601) + @example(duration.fromISO("P1Y1D")) + @summary("Interval") + interval: duration | null; /** * The rate cards of the plan. @@ -94,11 +94,12 @@ model PlanPhase { @summary("Discount") discount?: PlanDiscount; - /** - * Predefined overrides of the plan that can apply changes to the rate cards, discounts, and other properties based on the selected variant. - */ - @summary("Variants") - variants?: PlanVariantOverridePreset[] = #[]; + // NOTE(chrisgacsal): variants is going to be implemented in future releases + // /** + // * Predefined overrides of the plan that can apply changes to the rate cards, discounts, and other properties based on the selected variant. + // */ + // @summary("Variants") + // variants?: PlanVariantOverridePreset[] = #[]; } /** @@ -110,8 +111,8 @@ union PlanDiscount { @summary("Percentage discount") percentage: PlanDiscountPercentage, - @summary("Amount discount") - amount: PlanDiscountAmount, + // @summary("Amount discount") + // amount: PlanDiscountAmount, } /** @@ -129,20 +130,21 @@ model PlanDiscountPercentage { appliesToRateCards?: Key[]; } -/** - * Amount discount on plan. - */ -@friendlyName("PlanDiscountAmount") -model PlanDiscountAmount { - ...DiscountAmount; - - /** - * The rate cards that the discount applies to. - * When not specified, the discount applies to all rate cards. - */ - @summary("Applies To") - appliesToRateCards?: Key[]; -} +// NOTE(chrisgacsal): variants is going to be implemented in future releases +// /** +// * Amount discount on plan. +// */ +// @friendlyName("PlanDiscountAmount") +// model PlanDiscountAmount { +// ...DiscountAmount; + +// /** +// * The rate cards that the discount applies to. +// * When not specified, the discount applies to all rate cards. +// */ +// @summary("Applies To") +// appliesToRateCards?: Key[]; +// } /** * A plan variant. @@ -204,3 +206,20 @@ model PlanVariantOverridePreset { @summary("Discount") discount?: PlanDiscount; } + +/** + * Order by options for plans. + */ +@friendlyName("PlanOrderBy") +enum PlanOrderBy { + id: "id", + key: "key", +} + +/** + * Order by options for plan phases. + */ +@friendlyName("PhasesOrderBy") +enum PhasesOrderBy { + key: "key", +} diff --git a/api/spec/src/prices.tsp b/api/spec/src/productcatalog/prices.tsp similarity index 92% rename from api/spec/src/prices.tsp rename to api/spec/src/productcatalog/prices.tsp index fb8501abd..b2f55de07 100644 --- a/api/spec/src/prices.tsp +++ b/api/spec/src/productcatalog/prices.tsp @@ -1,6 +1,4 @@ -import "./types.tsp"; - -namespace OpenMeter; +namespace OpenMeter.ProductCatalog; /** * The type of the price. @@ -45,6 +43,7 @@ union PricePaymentTerm { */ inArrears: "in_arrears", + // NOTE(chrisgacsal): prepaid might be implemented in future releases // /** // * If prepaid, entitlements will be granted only after invoice is paid // */ @@ -68,7 +67,9 @@ model FlatPrice { * Flat price with payment term. */ @friendlyName("FlatPriceWithPaymentTerm") -model FlatPriceWithPaymentTerm extends FlatPrice { +model FlatPriceWithPaymentTerm { + ...FlatPrice; + /** * The payment term of the flat price. * Defaults to in advance. @@ -169,7 +170,8 @@ model SpendCommitments { * Unit price with spend commitments. */ @friendlyName("UnitPriceWithCommitments") -model UnitPriceWithCommitments extends UnitPrice { +model UnitPriceWithCommitments { + ...UnitPrice; ...SpendCommitments; } @@ -177,6 +179,7 @@ model UnitPriceWithCommitments extends UnitPrice { * Tiered price with spend commitments. */ @friendlyName("TieredPriceWithCommitments") -model TieredPriceWithCommitments extends TieredPrice { +model TieredPriceWithCommitments { + ...TieredPrice; ...SpendCommitments; } diff --git a/api/spec/src/ratecards.tsp b/api/spec/src/productcatalog/ratecards.tsp similarity index 81% rename from api/spec/src/ratecards.tsp rename to api/spec/src/productcatalog/ratecards.tsp index 52e7e76f1..8ca4e7c79 100644 --- a/api/spec/src/ratecards.tsp +++ b/api/spec/src/productcatalog/ratecards.tsp @@ -1,11 +1,6 @@ -import "./types.tsp"; -import "./discounts.tsp"; -import "./prices.tsp"; -import "./entitlements/main.tsp"; -import "./billing/main.tsp"; - -namespace OpenMeter; +namespace OpenMeter.ProductCatalog; +using TypeSpec.OpenAPI; using OpenMeter.Entitlements; /** @@ -21,14 +16,15 @@ enum RateCardType { * Common fields of the rate card. */ @friendlyName("RateCardBase") -model RateCardBase { - ...Resource; +model RateCardBase { + ...OmitProperties; /** - * The type of the rate card + * The type of the RateCard. */ - @summary("Type of the rate card") - type: RateCardType; + @visibility("read", "create") + @summary("Channel Type") + type: T; /** * The feature the customer is entitled to use. @@ -56,6 +52,7 @@ model RateCardBase { */ @friendlyName("RateCard") @discriminator("type") +@oneOf union RateCard { flatFee: RateCardFlatFee, usageBased: RateCardUsageBased, @@ -65,8 +62,8 @@ union RateCard { * A flat fee rate card defines a one-time purchase or a recurring fee. */ @friendlyName("RateCardFlatFee") -model RateCardFlatFee extends RateCardBase { - type: RateCardType.flatFee; +model RateCardFlatFee { + ...RateCardBase; /** * The billing cadence of the rate card. @@ -84,20 +81,21 @@ model RateCardFlatFee extends RateCardBase { @example(#{ type: PriceType.flat, amount: "100", paymentTerm: "in_arrears" }) price: FlatPriceWithPaymentTerm | null; - /** - * The discount of the rate card. Either a percentage or an amount. - * Only available when price is set. - */ - @summary("Discount") - discount?: DiscountPercentage | DiscountAmount; + // NOTE(chrisgacsal): discount on RateCard level going to be implemented in upcoming releases + // /** + // * The discount of the rate card. Either a percentage or an amount. + // * Only available when price is set. + // */ + // @summary("Discount") + // discount?: DiscountPercentage | DiscountAmount; } /** * A usage-based rate card defines a price based on usage. */ @friendlyName("RateCardUsageBased") -model RateCardUsageBased extends RateCardBase { - type: RateCardType.usageBased; +model RateCardUsageBased { + ...RateCardBase; /** * The billing cadence of the rate card. @@ -136,7 +134,7 @@ union RateCardOverride { */ @friendlyName("RateCardOverrideFlatFee") model RateCardOverrideFlatFee { - ...PickProperties; + ...PickProperties; } /** @@ -144,7 +142,7 @@ model RateCardOverrideFlatFee { */ @friendlyName("RateCardOverrideUsageBased") model RateCardOverrideUsageBased { - ...PickProperties; + ...PickProperties; } /** @@ -165,7 +163,7 @@ union RateCardEntitlement { @friendlyName("RateCardMeteredEntitlement") model RateCardMeteredEntitlement { ...OmitProperties< - EntitlementMeteredCreateInputs, + OpenMeter.Entitlements.EntitlementMeteredCreateInputs, "featureKey" | "featureId" | "usagePeriod" | "measureUsageFrom" | "isUnlimited" >; diff --git a/api/spec/src/productcatalog/routes.tsp b/api/spec/src/productcatalog/routes.tsp new file mode 100644 index 000000000..98a4da35f --- /dev/null +++ b/api/spec/src/productcatalog/routes.tsp @@ -0,0 +1,208 @@ +namespace OpenMeter.ProductCatalog; + +using TypeSpec.Http; +using TypeSpec.OpenAPI; + +alias PlanIdOrKey = ULID | Key; + +@route("/api/v1/plans") +@tag("Plan (Experimental)") +interface Plans { + /** + * List all plans. + */ + @get + @operationId("listPlans") + @summary("List plans") + list( + /** + * Include deleted plans in response. + * + * Usage: `?includeDeleted=true` + */ + @query + @example(true) + includeDeleted?: boolean = false, + + /** + * Filter by plan.id attribute + */ + @query(#{ explode: true }) + id?: ULID[], + + /** + * Filter by plan.key attribute + */ + @query(#{ explode: true }) + key?: Key[], + + /** + * Filter by plan.key and plan.version attributes + */ + @query(#{ explode: true, style: "deepObject" }) + keyVersion?: Record, + + ...OpenMeter.QueryPagination, + ...OpenMeter.QueryOrdering, + ): OpenMeter.PaginatedResponse | OpenMeter.CommonErrors; + + /** + * Create a new plan. + */ + @post + @operationId("createPlan") + @summary("Create a plan") + create(@body request: TypeSpec.Rest.Resource.ResourceCreateModel): { + @statusCode _: 201; + @bodyRoot body: Plan; + } | OpenMeter.CommonErrors; + + /** + * Update plan by id. + */ + @put + @operationId("updatePlan") + @summary("Update a plan") + update( + @path planId: ULID, + @body request: TypeSpec.Rest.Resource.ResourceCreateOrUpdateModel, + ): Plan | OpenMeter.NotFoundError | OpenMeter.CommonErrors; + + /** + * Get a plan by id or key. The latest published version is returned if latter is used. + */ + @get + @operationId("getPlan") + @summary("Get plan") + get( + @extension("x-go-type", "string") + @path + planId: PlanIdOrKey, + ): Plan | OpenMeter.NotFoundError | OpenMeter.CommonErrors; + + /** + * Soft delete plan by plan.id. + * + * Once a plan is deleted it cannot be undeleted. + */ + @delete + @operationId("deletePlan") + @summary("Delete plan") + delete(@path planId: ULID): { + @statusCode _: 204; + } | OpenMeter.NotFoundError | OpenMeter.CommonErrors; +} + +@route("/api/v1/plans/{planId}/publish") +@tag("Plan (Experimental)") +interface PlanPublish { + /** + * Publish a new plan. + */ + @post + @operationId("publishPlan") + @summary("Publish plan") + publish(@path planId: ULID): { + @statusCode _: 204; + } | OpenMeter.NotFoundError | OpenMeter.CommonErrors; +} + +@route("/api/v1/plans/{planId}/unpublish") +@tag("Plan (Experimental)") +interface PlanUnpublish { + /** + * Unpublish a new plan. + */ + @post + @operationId("unpublishPlan") + @summary("Unpublish plan") + unpublish(@path planId: ULID): { + @statusCode _: 204; + } | OpenMeter.NotFoundError | OpenMeter.CommonErrors; +} + +@route("/api/v1/plans/{planId}/next") +@tag("Plan (Experimental)") +interface PlanNewDraftVersion { + /** + * Create a new draft version from plan. + * It returns error if there is already a plan in draft or planId does not reference the latest published version. + */ + @post + @operationId("newDraftPlan") + @summary("New draft plan") + next( + @extension("x-go-type", "string") + @path + planId: PlanIdOrKey, + ): { + @statusCode _: 201; + @bodyRoot body: Plan; + } | OpenMeter.NotFoundError | OpenMeter.CommonErrors; +} + +@route("/api/v1/plans/{planId}/phases") +@tag("Plan (Experimental)") +interface PlanPhases { + /** + * List all phases in plan. + */ + @get + @operationId("listPlanPhases") + @summary("List phases in plan") + list( + @path planId: ULID, + + /** + * Filter by phase.key attribute + */ + @query(#{ explode: true }) + key?: Key[], + + ...OpenMeter.QueryPagination, + ...OpenMeter.QueryOrdering, + ): OpenMeter.PaginatedResponse | OpenMeter.CommonErrors; + + /** + * Create new phase in plan. + */ + @post + @operationId("createPlanPhases") + @summary("Create new phase in plan") + create(@path planId: ULID, @body request: TypeSpec.Rest.Resource.ResourceCreateModel): { + @statusCode _: 201; + @bodyRoot body: PlanPhase; + } | OpenMeter.CommonErrors; + + /** + * Update phase in plan. + */ + @put + @operationId("updatePlanPhases") + @summary("Update phase in plan") + update( + @path planId: ULID, + @path planPhaseKey: Key, + @body request: TypeSpec.Rest.Resource.ResourceCreateOrUpdateModel, + ): PlanPhase | OpenMeter.NotFoundError | OpenMeter.CommonErrors; + + /** + * Get phase in plan. + */ + @get + @operationId("getPlanPhases") + @summary("Get phase for plan") + get(@path planId: ULID, @path planPhaseKey: Key): PlanPhase | OpenMeter.NotFoundError | OpenMeter.CommonErrors; + + /** + * Delete phase in plan. + * + * Once a phase is deleted it cannot be undeleted. + */ + @delete + @operationId("deletePlanPhases") + @summary("Delete phase for plan") + delete(@path planId: ULID, @path planPhaseKey: Key): { + @statusCode _: 204; + } | OpenMeter.NotFoundError | OpenMeter.CommonErrors; +} diff --git a/api/spec/src/types.tsp b/api/spec/src/types.tsp index d4568265e..d5c2f8c8c 100644 --- a/api/spec/src/types.tsp +++ b/api/spec/src/types.tsp @@ -61,6 +61,7 @@ model UniqueResource { /** * A semi-unique identifier for the resource. */ + @visibility("read", "create") @summary("Key") key: Key; } diff --git a/openmeter/server/router/plan.go b/openmeter/server/router/plan.go new file mode 100644 index 000000000..d67c731f8 --- /dev/null +++ b/openmeter/server/router/plan.go @@ -0,0 +1,85 @@ +package router + +import ( + "net/http" + + "github.com/openmeterio/openmeter/api" +) + +// List plans +// (GET /api/v1/plans) +func (a *Router) ListPlans(w http.ResponseWriter, r *http.Request, params api.ListPlansParams) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Create a plan +// (POST /api/v1/plans) +func (a *Router) CreatePlan(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Delete plan +// (DELETE /api/v1/plans/{planId}) +func (a *Router) DeletePlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Get plan +// (GET /api/v1/plans/{planId}) +func (a *Router) GetPlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Update a plan +// (PUT /api/v1/plans/{planId}) +func (a *Router) UpdatePlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// New draft plan +// (POST /api/v1/plans/{planId}/next) +func (a *Router) NewDraftPlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// List phases in plan +// (GET /api/v1/plans/{planId}/phases) +func (a *Router) ListPlanPhases(w http.ResponseWriter, r *http.Request, planId string, params api.ListPlanPhasesParams) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Create new phase in plan +// (POST /api/v1/plans/{planId}/phases) +func (a *Router) CreatePlanPhases(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Delete phase for plan +// (DELETE /api/v1/plans/{planId}/phases/{planPhaseKey}) +func (a *Router) DeletePlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Get phase for plan +// (GET /api/v1/plans/{planId}/phases/{planPhaseKey}) +func (a *Router) GetPlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Update phase in plan +// (PUT /api/v1/plans/{planId}/phases/{planPhaseKey}) +func (a *Router) UpdatePlanPhases(w http.ResponseWriter, r *http.Request, planId string, planPhaseKey string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Publish plan +// (POST /api/v1/plans/{planId}/publish) +func (a *Router) PublishPlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Unpublish plan +// (POST /api/v1/plans/{planId}/unpublish) +func (a *Router) UnpublishPlan(w http.ResponseWriter, r *http.Request, planId string) { + w.WriteHeader(http.StatusNotImplemented) +}