Skip to content

Seats

A seat offer combines per-seat billing with a seat_capacity benefit. Checkout quantity determines both total price and contributed capacity.

import { Access, Billing, Offer, Purchase, Seats } from "@byfungsi/sapa";
import { Effect } from "effect";
const teamOffer = Effect.gen(function* () {
const access = yield* Access.entitlements({
entitlements: ["team.use"],
duration: "purchased_period",
});
const capacity = yield* Seats.capacity({
pool: "team.members",
quantity: "purchase_quantity",
entitlement: "team.use",
});
const purchase = yield* Purchase.parse({
key: "team.seats.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: "team.seats",
revision: 1,
purchase,
billing,
});
});

Use selectOfferSeats before checkout when you need a pure validated quote.

import { assignSeat, checkSeatAssignmentAccess } from "@byfungsi/sapa";
import { Effect } from "effect";
const beneficiary = {
type: "merchant_subject",
subjectId: "workspace-42",
} as const;
const program = Effect.gen(function* () {
const assignment = yield* assignSeat({
idempotencyKey: "workspace-42-member-7-assignment-1",
beneficiary,
pool: "team.members",
memberId: "member-7",
principal: "workspace-admin-3",
});
const access = yield* checkSeatAssignmentAccess({
beneficiary,
pool: "team.members",
memberId: "member-7",
entitlement: "team.use",
});
return { assignment, access };
});

Unassign with the returned assignmentId and a new idempotency key. Historical occupancy remains append-only.

Assignments cannot exceed active capacity. Access also denies the entire pool if retained active assignments exceed current active capacity—for example after a refund or plan decrease—rather than choosing arbitrary winners.