Skip to content

Payments and refunds

SAPA accepts raw provider notifications through one operation:

import { processPaymentNotification } from "@byfungsi/sapa";
const result = processPaymentNotification({
provider: "midtrans",
payload: rawRequestBody,
});

Pass the exact raw body. The selected provider adapter is responsible for authentication, signature verification, parsing, and normalization.

PaymentNotificationResult is discriminated by status:

  • ignored — authenticated but not a settled lifecycle observation.
  • settled — payment was accepted; access, seat capacity, credit lots, and fulfillment obligations were atomically derived.
  • refunded — reversible benefits were revoked and reversal work retained.
  • failed or expired — checkout reached a terminal non-payment state.

Every replayable result includes replayed. Duplicate authenticated provider delivery is normal and must return the retained outcome.

Map typed outcomes to your provider’s expected acknowledgement. A safe handler usually:

  1. applies a strict body-size limit before reading the payload;
  2. calls processPaymentNotification once;
  3. acknowledges accepted, ignored, and replayed notifications;
  4. rejects invalid_notification without exposing verification details;
  5. retries or alerts on internal_error according to provider semantics.

Do not log the raw payload, signatures, credentials, or customer data by default. Do not grant access from browser redirects; redirects are not authoritative settlement evidence.

Refund acceptance appends reversal history. It does not delete the original payment or overwrite historical terms. Perpetual access, active seat capacity, unused credit lots, pending fulfillment, and licenses respond according to their own lifecycle rules and retained provenance.