Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions api/spec/packages/aip-client-javascript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ export type {
ListCurrenciesParamsFilter,
CurrencyCustom,
CreateCurrencyCustomRequest,
UnitConfig,
GovernanceQueryRequest,
GovernanceFeatureAccessReason,
GovernanceQueryError,
UnitConfig,
AppCustomerData,
UpsertAppCustomerDataRequest,
CreditAdjustment,
Expand Down Expand Up @@ -233,8 +233,8 @@ export type {
CreateTaxCodeRequest,
TaxCode,
UpsertTaxCodeRequest,
GovernanceFeatureAccess,
InvoiceUsageQuantityDetail,
GovernanceFeatureAccess,
CustomerData,
UpsertCustomerBillingDataRequest,
CreditBalances,
Expand Down Expand Up @@ -309,8 +309,8 @@ export type {
CreateCreditGrantPurchaseInput,
RateCardMeteredEntitlementInput,
CreditGrantPurchaseInput,
GovernanceQueryRequestInput,
UnitConfigInput,
GovernanceQueryRequestInput,
IngestedEventInput,
SubscriptionCancelInput,
InvoiceUsageQuantityDetailInput,
Expand Down
107 changes: 54 additions & 53 deletions api/spec/packages/aip-client-javascript/src/models/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,20 @@ export const planStatus = z
'The status of a plan. - `draft`: The plan has not yet been published and can be edited. - `active`: The plan is published and can be used in subscriptions. - `archived`: The plan is no longer available for use. - `scheduled`: The plan is scheduled to be published at a future date.',
)

export const unitConfigOperation = z
.enum(['divide', 'multiply'])

.describe(
'The arithmetic operation used to convert raw metered units into billing units. - `divide`: Divide the metered quantity by the conversion factor (e.g., bytes ÷ 1e9 = GB). - `multiply`: Multiply the metered quantity by the conversion factor (e.g., cost × 1.2 = cost + 20% margin).',
)

export const unitConfigRoundingMode = z
.enum(['ceiling', 'floor', 'half_up', 'none'])

.describe(
'The rounding mode applied to the converted quantity for invoicing. Rounding is applied only to the invoiced quantity. Entitlement balance checks use the precise decimal value after conversion. - `ceiling`: Round up to the next integer (typical for package-style billing). - `floor`: Round down to the previous integer. - `half_up`: Round to the nearest integer, with 0.5 rounding up. - `none`: No rounding; the converted value is used as-is.',
)

export const rateCardStaticEntitlement = z
.object({
type: z.literal('static').describe('The type of the entitlement template.'),
Expand Down Expand Up @@ -1128,20 +1142,6 @@ export const collectionMethod = z
'Collection method specifies how the invoice should be collected (automatic or manual).',
)

export const unitConfigOperation = z
.enum(['divide', 'multiply'])

.describe(
'The arithmetic operation used to convert raw metered units into billing units. - `divide`: Divide the metered quantity by the conversion factor (e.g., bytes ÷ 1e9 = GB). - `multiply`: Multiply the metered quantity by the conversion factor (e.g., cost × 1.2 = cost + 20% margin).',
)

export const unitConfigRoundingMode = z
.enum(['ceiling', 'floor', 'half_up', 'none'])

.describe(
'The rounding mode applied to the converted quantity for invoicing. Rounding is applied only to the invoiced quantity. Entitlement balance checks use the precise decimal value after conversion. - `ceiling`: Round up to the next integer (typical for package-style billing). - `floor`: Round down to the previous integer. - `half_up`: Round to the nearest integer, with 0.5 rounding up. - `none`: No rounding; the converted value is used as-is.',
)

export const priceType = z
.enum(['free', 'flat', 'unit', 'graduated', 'volume'])

Expand Down Expand Up @@ -2589,6 +2589,33 @@ export const createCurrencyCustomRequest = z
})
.describe('CurrencyCustom create request.')

export const unitConfig = z
.object({
operation: unitConfigOperation,
conversion_factor: numeric,
rounding: unitConfigRoundingMode.optional().default('none'),
precision: z
.number()
.int()
.optional()
.default(0)

.describe(
'The number of decimal places to retain after rounding. Only meaningful when rounding is not "none". Defaults to 0 (round to whole numbers).',
),
display_unit: z
.string()
.optional()

.describe(
'A human-readable label for the converted unit shown on invoices and in the customer portal (e.g., "GB", "hours", "M tokens"). Optional. When omitted, no unit label is rendered.',
),
})

.describe(
'Unit conversion configuration. Transforms raw metered quantities into billing-ready units before pricing and entitlement evaluation. Applied at the rate card level so the same feature can be billed in different units across plans. Examples: - Meter bytes, bill GB: operation=divide, conversionFactor=1e9, rounding=ceiling, displayUnit="GB" - Meter seconds, bill hours: operation=divide, conversionFactor=3600, rounding=ceiling, displayUnit="hours" - Cost + 20% margin: operation=multiply, conversionFactor=1.2 - Bill per million tokens: operation=divide, conversionFactor=1e6, rounding=ceiling, displayUnit="M" v1 equivalents: - DynamicPrice(multiplier): operation=multiply, conversionFactor=multiplier + UnitPrice(amount=1) - PackagePrice(amount, quantityPerPkg): operation=divide, conversionFactor=quantityPerPkg, rounding=ceiling + UnitPrice(amount)',
)

export const governanceQueryRequest = z
.object({
include_credits: z
Expand Down Expand Up @@ -2636,33 +2663,6 @@ export const governanceQueryError = z
'Query error within a partially successful governance query response.',
)

export const unitConfig = z
.object({
operation: unitConfigOperation,
conversion_factor: numeric,
rounding: unitConfigRoundingMode.optional().default('none'),
precision: z
.number()
.int()
.optional()
.default(0)

.describe(
'The number of decimal places to retain after rounding. Only meaningful when rounding is not "none". Defaults to 0 (round to whole numbers).',
),
display_unit: z
.string()
.optional()

.describe(
'A human-readable label for the converted unit shown on invoices and in the customer portal (e.g., "GB", "hours", "M tokens"). Optional. When omitted, no unit label is rendered.',
),
})

.describe(
'Unit conversion configuration. Transforms raw metered quantities into billing-ready units before pricing and entitlement evaluation. Applied at the rate card level so the same feature can be billed in different units across plans. Examples: - Meter bytes, bill GB: operation=divide, conversionFactor=1e9, rounding=ceiling, displayUnit="GB" - Meter seconds, bill hours: operation=divide, conversionFactor=3600, rounding=ceiling, displayUnit="hours" - Cost + 20% margin: operation=multiply, conversionFactor=1.2 - Bill per million tokens: operation=divide, conversionFactor=1e6, rounding=ceiling, displayUnit="M" v1 equivalents: - DynamicPrice(multiplier): operation=multiply, conversionFactor=multiplier + UnitPrice(amount=1) - PackagePrice(amount, quantityPerPkg): operation=divide, conversionFactor=quantityPerPkg, rounding=ceiling + UnitPrice(amount)',
)

export const appCustomerData = z
.object({
stripe: appCustomerDataStripe.optional(),
Expand Down Expand Up @@ -3571,18 +3571,6 @@ export const currency = z
.discriminatedUnion('type', [currencyFiat, currencyCustom])
.describe('Fiat or custom currency.')

export const governanceFeatureAccess = z
.object({
has_access: z
.boolean()

.describe(
'Whether the customer currently has access to the feature. `true` for boolean and static entitlements that are available, and for metered entitlements with remaining balance. `false` when the feature is unavailable, the usage limit has been reached, or (when applicable) credits have been exhausted.',
),
reason: governanceFeatureAccessReason.optional(),
})
.describe('Access status for a single feature.')

export const invoiceUsageQuantityDetail = z
.object({
raw_quantity: numeric,
Expand All @@ -3600,6 +3588,18 @@ export const invoiceUsageQuantityDetail = z
'Usage quantity details on an invoice line item when UnitConfig is in effect. Provides the full audit trail from raw meter output to the invoiced amount.',
)

export const governanceFeatureAccess = z
.object({
has_access: z
.boolean()

.describe(
'Whether the customer currently has access to the feature. `true` for boolean and static entitlements that are available, and for metered entitlements with remaining balance. `false` when the feature is unavailable, the usage limit has been reached, or (when applicable) credits have been exhausted.',
),
reason: governanceFeatureAccessReason.optional(),
})
.describe('Access status for a single feature.')

export const customerData = z
.object({
billing_profile: profileReference.optional(),
Expand Down Expand Up @@ -4313,6 +4313,7 @@ export const rateCard = z
feature: featureReference.optional(),
billing_cadence: iso8601Duration.optional(),
price: price,
unit_config: unitConfig.optional(),
payment_term: pricePaymentTerm.optional().default('in_arrears'),
commitments: spendCommitments.optional(),
discounts: rateCardDiscounts.optional(),
Expand Down
62 changes: 33 additions & 29 deletions api/spec/packages/aip-client-javascript/src/models/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,20 @@ export interface CreateCurrencyCustomRequest {
code: string
}

/** Unit conversion configuration. Transforms raw metered quantities into billing-ready units before pricing and entitlement evaluation. Applied at the rate card level so the same feature can be billed in different units across plans. Examples: - Meter bytes, bill GB: operation=divide, conversionFactor=1e9, rounding=ceiling, displayUnit="GB" - Meter seconds, bill hours: operation=divide, conversionFactor=3600, rounding=ceiling, displayUnit="hours" - Cost + 20% margin: operation=multiply, conversionFactor=1.2 - Bill per million tokens: operation=divide, conversionFactor=1e6, rounding=ceiling, displayUnit="M" v1 equivalents: - DynamicPrice(multiplier): operation=multiply, conversionFactor=multiplier + UnitPrice(amount=1) - PackagePrice(amount, quantityPerPkg): operation=divide, conversionFactor=quantityPerPkg, rounding=ceiling + UnitPrice(amount) */
export interface UnitConfig {
/** The arithmetic operation to apply to the raw metered quantity. */
operation: 'divide' | 'multiply'
/** The factor used in the conversion operation. - For `divide`: `converted = raw / conversionFactor`. - For `multiply`: `converted = raw × conversionFactor`. Must be a positive non-zero value. */
conversion_factor: string
/** The rounding mode applied to the converted quantity for invoicing. Defaults to none (no rounding). Entitlement checks always use the precise (unrounded) value. */
rounding: 'ceiling' | 'floor' | 'half_up' | 'none'
/** The number of decimal places to retain after rounding. Only meaningful when rounding is not "none". Defaults to 0 (round to whole numbers). */
precision: number
/** A human-readable label for the converted unit shown on invoices and in the customer portal (e.g., "GB", "hours", "M tokens"). Optional. When omitted, no unit label is rendered. */
display_unit?: string
}

/** Query to evaluate feature access for a list of customers. */
export interface GovernanceQueryRequest {
/** Whether to include credit balance availability for each resolved customer. When true, each feature evaluation includes credit balance checks. Defaults to `false`. */
Expand Down Expand Up @@ -1447,20 +1461,6 @@ export interface GovernanceQueryError {
customer?: string
}

/** Unit conversion configuration. Transforms raw metered quantities into billing-ready units before pricing and entitlement evaluation. Applied at the rate card level so the same feature can be billed in different units across plans. Examples: - Meter bytes, bill GB: operation=divide, conversionFactor=1e9, rounding=ceiling, displayUnit="GB" - Meter seconds, bill hours: operation=divide, conversionFactor=3600, rounding=ceiling, displayUnit="hours" - Cost + 20% margin: operation=multiply, conversionFactor=1.2 - Bill per million tokens: operation=divide, conversionFactor=1e6, rounding=ceiling, displayUnit="M" v1 equivalents: - DynamicPrice(multiplier): operation=multiply, conversionFactor=multiplier + UnitPrice(amount=1) - PackagePrice(amount, quantityPerPkg): operation=divide, conversionFactor=quantityPerPkg, rounding=ceiling + UnitPrice(amount) */
export interface UnitConfig {
/** The arithmetic operation to apply to the raw metered quantity. */
operation: 'divide' | 'multiply'
/** The factor used in the conversion operation. - For `divide`: `converted = raw / conversionFactor`. - For `multiply`: `converted = raw × conversionFactor`. Must be a positive non-zero value. */
conversion_factor: string
/** The rounding mode applied to the converted quantity for invoicing. Defaults to none (no rounding). Entitlement checks always use the precise (unrounded) value. */
rounding: 'ceiling' | 'floor' | 'half_up' | 'none'
/** The number of decimal places to retain after rounding. Only meaningful when rounding is not "none". Defaults to 0 (round to whole numbers). */
precision: number
/** A human-readable label for the converted unit shown on invoices and in the customer portal (e.g., "GB", "hours", "M tokens"). Optional. When omitted, no unit label is rendered. */
display_unit?: string
}

/** App customer data. */
export interface AppCustomerData {
/** Used if the customer has a linked Stripe app. */
Expand Down Expand Up @@ -2360,14 +2360,6 @@ export interface UpsertTaxCodeRequest {
app_mappings: TaxCodeAppMapping[]
}

/** Access status for a single feature. */
export interface GovernanceFeatureAccess {
/** Whether the customer currently has access to the feature. `true` for boolean and static entitlements that are available, and for metered entitlements with remaining balance. `false` when the feature is unavailable, the usage limit has been reached, or (when applicable) credits have been exhausted. */
has_access: boolean
/** Optional reason when the customer does not have access to the feature. Populated when `has_access` is `false`. */
reason?: GovernanceFeatureAccessReason
}

/** Usage quantity details on an invoice line item when UnitConfig is in effect. Provides the full audit trail from raw meter output to the invoiced amount. */
export interface InvoiceUsageQuantityDetail {
/** The raw quantity as reported by the meter (native units). */
Expand All @@ -2382,6 +2374,14 @@ export interface InvoiceUsageQuantityDetail {
applied_unit_config: UnitConfig
}

/** Access status for a single feature. */
export interface GovernanceFeatureAccess {
/** Whether the customer currently has access to the feature. `true` for boolean and static entitlements that are available, and for metered entitlements with remaining balance. `false` when the feature is unavailable, the usage limit has been reached, or (when applicable) credits have been exhausted. */
has_access: boolean
/** Optional reason when the customer does not have access to the feature. Populated when `has_access` is `false`. */
reason?: GovernanceFeatureAccessReason
}

/** Billing customer data. */
export interface CustomerData {
/** The billing profile for the customer. If not provided, the default billing profile will be used. */
Expand Down Expand Up @@ -2925,6 +2925,8 @@ export interface RateCard {
billing_cadence?: string
/** The price of the rate card. */
price: PriceFree | PriceFlat | PriceUnit | PriceGraduated | PriceVolume
/** Unit conversion configuration for the rate card. Synthesized on read for plans authored with v1 dynamic or package prices: dynamic prices map to a unit price with a multiply unit config, and package prices map to a unit price with a divide unit config. Not yet accepted on create or update. */
unit_config?: UnitConfig
/** The payment term of the rate card. In advance payment term can only be used for flat prices. */
payment_term: 'in_advance' | 'in_arrears'
/** Spend commitments for this rate card. Only applicable to usage-based prices (unit, graduated, volume). */
Expand Down Expand Up @@ -3319,13 +3321,6 @@ export interface CreditGrantPurchaseInput {
settlement_status?: 'pending' | 'authorized' | 'settled'
}

export interface GovernanceQueryRequestInput {
/** Whether to include credit balance availability for each resolved customer. When true, each feature evaluation includes credit balance checks. Defaults to `false`. */
include_credits?: boolean
customer: GovernanceQueryRequestCustomers
feature?: GovernanceQueryRequestFeatures
}

export interface UnitConfigInput {
/** The arithmetic operation to apply to the raw metered quantity. */
operation: 'divide' | 'multiply'
Expand All @@ -3339,6 +3334,13 @@ export interface UnitConfigInput {
display_unit?: string
}

export interface GovernanceQueryRequestInput {
/** Whether to include credit balance availability for each resolved customer. When true, each feature evaluation includes credit balance checks. Defaults to `false`. */
include_credits?: boolean
customer: GovernanceQueryRequestCustomers
feature?: GovernanceQueryRequestFeatures
}

export interface IngestedEventInput {
/** The original event ingested. */
event: EventInput
Expand Down Expand Up @@ -3538,6 +3540,8 @@ export interface RateCardInput {
billing_cadence?: string
/** The price of the rate card. */
price: PriceFree | PriceFlat | PriceUnit | PriceGraduated | PriceVolume
/** Unit conversion configuration for the rate card. Synthesized on read for plans authored with v1 dynamic or package prices: dynamic prices map to a unit price with a multiply unit config, and package prices map to a unit price with a divide unit config. Not yet accepted on create or update. */
unit_config?: UnitConfigInput
/** The payment term of the rate card. In advance payment term can only be used for flat prices. */
payment_term?: 'in_advance' | 'in_arrears'
/** Spend commitments for this rate card. Only applicable to usage-based prices (unit, graduated, volume). */
Expand Down
13 changes: 13 additions & 0 deletions api/spec/packages/aip/src/productcatalog/ratecard.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "../features/index.tsp";
import "../tax/codes.tsp";
import "../entitlements/index.tsp";
import "./price.tsp";
import "./unitconfig.tsp";

namespace ProductCatalog;

Expand Down Expand Up @@ -55,6 +56,18 @@ model RateCard {
@summary("Price")
price: Price;

/**
* Unit conversion configuration for the rate card.
*
* Synthesized on read for plans authored with v1 dynamic or package prices:
* dynamic prices map to a unit price with a multiply unit config, and package
* prices map to a unit price with a divide unit config. Not yet accepted on create
* or update.
*/
@visibility(Lifecycle.Read)
@summary("Unit config")
unit_config?: UnitConfig;

/**
* The payment term of the rate card. In advance payment term can only be used for
* flat prices.
Expand Down
Loading
Loading