Files
cfw-autumn/shared/api/customers/cusFeatures/apiBalanceV1.ts
2026-02-25 19:39:10 +00:00

168 lines
4.7 KiB
TypeScript

import { BillingMethod } from "@api/products/components/billingMethod";
import {
TierBehavior,
UsageTierSchema,
} from "@models/productModels/priceModels/priceConfig/usagePriceConfig";
import { z } from "zod/v4";
import { ApiFeatureV1Schema } from "../../features/apiFeatureV1";
import { ApiBalanceResetSchema, ApiBalanceRolloverSchema } from "./apiBalance";
export const API_BALANCE_V1_EXAMPLE = {
feature_id: "messages",
granted: 100,
remaining: 72,
usage: 28,
unlimited: false,
overage_allowed: false,
max_purchase: null,
next_reset_at: 1773851121437,
breakdown: [
{
id: "cus_ent_39qmLooixXLAqMywgXywjAz96rV",
plan_id: "pro_plan",
included_grant: 100,
prepaid_grant: 0,
remaining: 72,
usage: 28,
unlimited: false,
reset: {
interval: "month",
resets_at: 1773851121437,
},
price: null,
expires_at: null,
},
],
};
export const ApiBalanceBreakdownPriceSchema = z.object({
amount: z.number().optional().meta({
description: "The per-unit price amount.",
}),
tiers: z.array(UsageTierSchema).optional().meta({
description: "Tiered pricing configuration if applicable.",
}),
tier_behavior: z.enum(TierBehavior).optional().meta({
description:
"How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).",
}),
billing_units: z.number().meta({
description:
"The number of units per billing increment (eg. $9 / 250 units).",
}),
billing_method: z.enum(BillingMethod).meta({
description: "Whether usage is prepaid or billed pay-per-use.",
}),
max_purchase: z.number().nullable().meta({
description:
"Maximum quantity that can be purchased, or null for unlimited.",
}),
});
export const ApiBalanceBreakdownV1Schema = z.object({
object: z.literal("balance_breakdown").meta({
internal: true,
}),
id: z.string().default("").meta({
description: "The unique identifier for this balance breakdown.",
}),
plan_id: z.string().nullable().meta({
description:
"The plan ID this balance originates from, or null for standalone balances.",
}),
included_grant: z.number().meta({
description: "Amount granted from the plan's included usage.",
}),
prepaid_grant: z.number().meta({
description: "Amount granted from prepaid purchases or top-ups.",
}),
remaining: z.number().meta({
description: "Remaining balance available for use.",
}),
usage: z.number().meta({
description: "Amount consumed in the current period.",
}),
unlimited: z.boolean().meta({
description: "Whether this balance has unlimited usage.",
}),
reset: ApiBalanceResetSchema.nullable().meta({
description: "Reset configuration for this balance, or null if no reset.",
}),
price: ApiBalanceBreakdownPriceSchema.nullable().meta({
description:
"Pricing configuration if this balance has usage-based pricing.",
}),
expires_at: z.number().nullable().meta({
description:
"Timestamp when this balance expires, or null for no expiration.",
}),
overage: z.number().meta({
internal: true,
}),
});
export const ApiBalanceV1Schema = z
.object({
object: z.literal("balance").meta({
internal: true,
}),
feature_id: z.string().meta({
description: "The feature ID this balance is for.",
}),
feature: ApiFeatureV1Schema.optional().meta({
description: "The full feature object if expanded.",
}),
granted: z.number().meta({
description: "Total balance granted (included + prepaid).",
}),
remaining: z.number().min(0).meta({
description: "Remaining balance available for use.",
}),
usage: z.number().meta({
description: "Total usage consumed in the current period.",
}),
unlimited: z.boolean().meta({
description: "Whether this feature has unlimited usage.",
}),
overage_allowed: z.boolean().meta({
description:
"Whether usage beyond the granted balance is allowed (with overage charges).",
}),
max_purchase: z.number().nullable().meta({
description:
"Maximum quantity that can be purchased as a top-up, or null for unlimited.",
}),
next_reset_at: z.number().nullable().meta({
description:
"Timestamp when the balance will reset, or null for no reset.",
}),
breakdown: z.array(ApiBalanceBreakdownV1Schema).optional().meta({
description:
"Detailed breakdown of balance sources when stacking multiple plans or grants.",
}),
rollovers: z.array(ApiBalanceRolloverSchema).optional().meta({
description: "Rollover balances carried over from previous periods.",
}),
})
.meta({
examples: [API_BALANCE_V1_EXAMPLE],
});
export type ApiBalanceBreakdownPrice = z.infer<
typeof ApiBalanceBreakdownPriceSchema
>;
export type ApiBalanceBreakdownV1 = z.infer<typeof ApiBalanceBreakdownV1Schema>;
export type ApiBalanceV1 = z.infer<typeof ApiBalanceV1Schema>;