Skip to content

Diagram viewer

Scroll to zoom. Drag to pan.

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.

A provider adapter must:

  1. authenticate the exact raw notification payload;
  2. bind the notification to the expected provider and checkout;
  3. compare currency and exact amount before settlement;
  4. retain stable provider event identity for deduplication;
  5. classify pending, settled, failed, expired, and refunded observations;
  6. sanitize provider failures before they cross the facade;
  7. treat checkout-creation timeout as an unknown outcome;
  8. reconcile existing attempts without initiating duplicate creation.

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.

SAPA manages Polar products automatically. The first checkout for a logical purchasable leases its installation-scoped binding, searches Polar by SAPA metadata, and creates a private one-time product only when none exists. The binding is retained in D1 and later checkouts reuse it. A retry after process loss searches the same metadata before creating, so operators do not configure or copy Polar product IDs. The Polar organization token therefore needs products:read, products:write, and the checkout read/write scopes.

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.

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.

@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.