Payment providers
SAPA’s public facade is provider-neutral. A runtime installs a provider registry whose adapters create checkouts, authenticate notifications, normalize status, and reconcile retained attempts.
Required invariants
Section titled “Required invariants”A provider adapter must:
- authenticate the exact raw notification payload;
- bind the notification to the expected provider and checkout;
- compare currency and exact amount before settlement;
- retain stable provider event identity for deduplication;
- classify pending, settled, failed, expired, and refunded observations;
- sanitize provider failures before they cross the facade;
- treat checkout-creation timeout as an unknown outcome;
- reconcile existing attempts without initiating duplicate creation.
Webhook shape
Section titled “Webhook shape”Your HTTP route passes provider identity, the untouched raw body, and only the headers needed by the provider’s signature scheme:
import { processPaymentNotification } from "@byfungsi/sapa";
const operation = processPaymentNotification({ provider: "polar", payload: rawBody, headers: { "webhook-id": request.headers.get("webhook-id") ?? "", "webhook-timestamp": request.headers.get("webhook-timestamp") ?? "", "webhook-signature": request.headers.get("webhook-signature") ?? "", },});Do not parse and reserialize a signed payload unless the provider’s signature scheme explicitly requires that representation.
The Cloudflare reference runtime already exposes provider-specific routes. Polar
currently supports USD one-time checkout, authenticated order.paid, complete
order.refunded, and checkout.expired events. Partial refunds are authenticated
but ignored until Polar reports the cumulative full charged amount; SAPA never
revokes the complete purchase for a partial refund. Automatic recurring Polar
billing is not advertised until renewal orders can be mapped to SAPA subscription
cycles without reusing the initial checkout settlement.
Polar settlement compares SAPA’s price with net_amount, the amount after
discounts and before sales tax. A tax-inclusive total_amount may therefore be
higher without weakening the exact price check. A complete refund still requires
the cumulative refunded_amount to equal that tax-inclusive total.
Retry policy
Section titled “Retry policy”Network retries are not universally safe. Retrying an idempotent status read can
be safe; blindly retrying checkout creation can duplicate an external charge or
payment session. Preserve SAPA’s checkout ID and idempotency key, then use
recoverCheckout for reconciliation.
Availability in 0.1.0
Section titled “Availability in 0.1.0”@byfungsi/sapa exposes the provider-neutral facade. Concrete provider and
storage adapters are composed by the host deployment and are not separate
public npm entrypoints in 0.1.0.