Metered API
import { Access, Billing, Offer, Purchase, checkAccess, correctMeteredUsage, createCheckout, enrollPostpaidSubscription, finalizeMeteredInvoice, getMeteredInvoiceCollection, processPaymentNotification, recordMeteredUsage, registerOffers,} from "@byfungsi/sapa";
const apiAccess = yield * Access.entitlements({ entitlements: ["api.use"], duration: "purchased_period", });const apiPurchase = yield * Purchase.parse({ key: "api.metered.access", revision: 1, provides: [apiAccess], });const apiBilling = yield * Billing.meteredSubscription({ family: "api", interval: "month", meter: { key: "api.request", revision: 1 }, rate: { currency: "IDR", amount: 25n, perUnits: 10n, rounding: "trunc" }, accessPolicy: { key: "api.postpaid_access", revision: 1 }, });const meteredApi = yield * Offer.parse({ key: "api.metered", revision: 1, purchase: apiPurchase, billing: apiBilling, });
yield * registerOffers([meteredApi]);const enrollment = yield * enrollPostpaidSubscription({ idempotencyKey: "api-enrollment-42", externalCustomerId: "customer-42", offerKey: meteredApi.key, offerRevision: meteredApi.revision, });
yield * recordMeteredUsage({ idempotencyKey: "request-batch-2026-09-42", subscriptionId: enrollment.subscriptionId, meter: { key: "api.request", revision: 1 }, quantity: 120n, occurredAt: usageOccurredAt, });yield * correctMeteredUsage({ idempotencyKey: "request-correction-2026-09-42", originalUsageIdempotencyKey: "request-batch-2026-09-42", quantityDelta: -20n, correctedAt, });
const invoice = yield * finalizeMeteredInvoice({ subscriptionId: enrollment.subscriptionId, periodEndsAt, });if (invoice.collectionStatus === "payment_due") { yield * createCheckout({ type: "invoice", invoiceId: invoice.invoiceId, provider: "midtrans", customer, successUrl, cancelUrl, clientIp: null, idempotencyKey: `invoice-${invoice.invoiceId}`, });}
yield * processPaymentNotification({ provider: "midtrans", payload: rawProviderPayload, });const collection = yield * getMeteredInvoiceCollection(invoice.invoiceId);const granted = yield * checkAccess({ externalCustomerId: "customer-42", entitlement: "api.use" });Install meter api.request@1 and access policy api.postpaid_access@1 before
registration. Enrollment is an authenticated merchant decision, not a payment.
Record usage only from trusted servers. Finalize only after the exact current
period ends; 100 net units rate to IDR 250 after one aggregate rounding step.