Skip to content

SaaS subscriptions

import { Access, Billing, Limits, Offer, Purchase } from "@byfungsi/sapa";
import { Effect } from "effect";
export const proPlan = Effect.gen(function* () {
const access = yield* Access.entitlements({
entitlements: ["workspace.use"],
duration: "purchased_period",
});
const limit = yield* Limits.resource({
resource: "workspace.project",
quantity: 100,
entitlement: "workspace.use",
});
const purchase = yield* Purchase.parse({
key: "workspace.plan",
revision: 2,
provides: [access, limit],
});
const billing = yield* Billing.subscription({
family: "workspace",
price: { currency: "IDR", amount: 300_000n },
interval: "month",
});
return yield* Offer.parse({
key: "workspace.pro",
revision: 1,
purchase,
billing,
});
});

Basic and Pro can share purchase key workspace.plan but must use different purchase revisions because they promise different limits.

import { Seats } from "@byfungsi/sapa";
export const teamPlan = Effect.gen(function* () {
const access = yield* Access.entitlements({
entitlements: ["workspace.use"],
duration: "purchased_period",
});
const capacity = yield* Seats.capacity({
pool: "workspace.members",
quantity: "purchase_quantity",
entitlement: "workspace.use",
});
const purchase = yield* Purchase.parse({
key: "workspace.team.access",
revision: 1,
provides: [access, capacity],
});
const billing = yield* Billing.perSeatSubscription({
family: "workspace",
price: { currency: "IDR", amount: 75_000n },
minimumQuantity: 1,
maximumQuantity: 100,
interval: "month",
});
return yield* Offer.parse({
key: "workspace.team",
revision: 1,
purchase,
billing,
});
});

At checkout, set the beneficiary to the workspace and quantity to the purchased seat count. After settlement, use seat assignment operations for individual members. Schedule decreases only when current assignments fit the target.