const CUPRICE = "https://app.cuprice.io";
export type PlanFeature = { name: string; limit: number | null };
export type PricedPlan = {
cupricePlanId: number; // 0 for a custom plan
name: string;
amount: number;
currency: string;
interval: "month" | "year";
features: PlanFeature[];
};
function toPricedPlan(payload: any): PricedPlan {
return {
cupricePlanId: payload.plan.id,
name: payload.plan.name,
amount: Math.round(payload.plan.amount * 100) / 100, // annual amounts can carry float noise
currency: payload.plan.currency,
interval: payload.plan.interval,
features: payload.features
.filter((f: any) => f.included)
.map((f: any) => ({ name: f.name, limit: f.limit })),
};
}
// A regular plan, by cuprice_plan_id
export async function pricePlan(shareId: string, planId: string, interval: string) {
const res = await fetch(
`${CUPRICE}/api/share/${shareId}/checkout-payload?planId=${planId}&billingInterval=${interval}`,
{ cache: "no-store" }
);
const { payload } = await res.json();
if (!payload) throw new Error(`Cuprice plan ${planId} not found`);
return toPricedPlan(payload);
}
// A custom plan, from selected_features and feature_usage
export async function priceCustomPlan(
shareId: string,
names: string[],
usage: Record<string, number>
) {
const res = await fetch(`${CUPRICE}/api/share/${shareId}/checkout-payload`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
selectedFeatures: names.map((name) => ({ name })),
featureUsageAmounts: usage,
billingInterval: "month",
}),
cache: "no-store",
});
const { payload } = await res.json();
if (!payload) throw new Error("Could not price the custom plan");
return toPricedPlan(payload);
}