PayFanout API reference
    Preparing search index...

    The Paysafe server adapter: the Payments API, Customer Vault and Payment Scheduler over REST, tokenize-first.

    Paysafe reads amounts in the minor units of its currency table, and the adapter sends PayFanout's unchanged and converts none, so it refuses a currency the table gives another exponent than PayFanout (CLP, BYR), or one the table lacks that is not priced in hundredths (ISK, UYI and others; see "Currencies the adapter refuses" in the setup guide), and declares them in unsupportedCurrencies, so the router skips Paysafe for a session in one and PaymentService refuses it with unsupported_operation (from the @payfanout/server release that reads the field). createPaymentSession and updatePaymentSession refuse one with invalid_request before any request. completePayment, chargeSavedPaymentMethod and createNativeSubscription, which earlier releases sent in such currencies, look their key up first, a read that moves no money, and refuse with invalid_request, marked outcomeUnknown when Paysafe holds something under the key or the lookup fails. capturePayment and refundPayment read the payment first and refuse with invalid_request when they carry an amount, which is in PayFanout's minor units, and with unsupported_operation when they carry none, as cancelPayment does: those send Paysafe's own amounts, or none, but answer with amounts that cannot be reported in PayFanout's minor units. cancelNativeSubscription reads the subscription first and refuses the same way. retrievePayment, retrieveRefund (for a refund Paysafe reports in such a currency), retrieveNativeSubscription and listNativeSubscriptions refuse with unsupported_operation, and webhook events in one carry no amount.

    Implements

    Index
    pspName: "paysafe" = PAYSAFE_PSP_NAME
    • PATCH /subscriptions/{id} to CANCELLED — the FINAL status ("cannot be re-activated"); SUSPENDED is the reversible pause and is deliberately not used here. Verified-idempotent: the scheduler does not document patching an already-terminal subscription, so on any rejection the adapter re-fetches and treats CANCELLED/COMPLETED as success — billing that is already stopped never fails a replayed cancel, except in a currency the adapter refuses (below). The PATCH carries no merchantRefNum (the scheduler has none there); replay safety comes from CANCELLED being absorbing plus that re-fetch, which is why the required idempotencyKey has no wire mapping on this call.

      The subscription is read before the PATCH, one more request on every cancel, and a failed read fails the cancel before anything is sent. One in a currency the adapter refuses is refused there with unsupported_operation, since the answer could not report its amounts, even when it is already stopped and its cancel would otherwise succeed.

      Returns Promise<NativeSubscriptionRecord>

    • Voids the remaining authorization. This also works AFTER partial settlements (multi-capture flows) — settled funds stay settled and the returned PaymentInfo reports them (status "succeeded"), derived from the amount the void released; only a payment with no settlements at all comes back "canceled". Partial captures settle under the caller's keys, which no read can rediscover (see capturePayment), so LATER retrievePayment calls lose that split once the void has consumed availableToSettle (documented limitation).

      Parameters

      • pspPaymentId: string
      • idempotencyKey: string

      Returns Promise<PaymentInfo>

    • Settles an authorization, in full or in part. Refunds come out of settlements, and Paysafe finds a settlement again only by its merchantRefNum, so the reference decides what refundPayment can reach later.

      A full capture, amount omitted (everything that remains) or equal to the authorized amount, settles under a reference derived from the payment, never under idempotencyKey: payfanout-capture-<payment id>, or, once the settlements there have moved no money (failed, cancelled or expired), the next of -a2 to -a10. Those references are read first: a settlement there that moved money means the payment is captured in full, and the call answers with it whatever its key, unless it asks for the authorized amount and that settlement settled another (the rest, after partial captures), which is refused as already captured in full. With no such settlement, a capture of the authorized amount that the payment read shows partial captures have left short is refused before it is sent, and one with nothing left to settle is refused as nothing left to capture. retrievePayment and refundPayment read the same references.

      A partial capture, any other amount, settles under idempotencyKey, which must be unique across the account and may not start with payfanout-capture-. No read finds its settlement from the payment: its amount counts in amountCaptured, but refundPayment cannot refund it.

      The answer is the payment as read after the capture, with no settlement lookup after the write, so an outage then cannot fail a capture that settled. Its raw is the payment with one more property, captureSettlement: the settlement this capture made, or the one it read back or met. Keep a partial capture's id to find that settlement in the Paysafe portal and refund it there.

      Parameters

      • pspPaymentId: string
      • amount: number | undefined
      • idempotencyKey: string

      Returns Promise<PaymentInfo>

    • Creates a subscription the scheduler bills itself, against an already-vaulted MULTI_USE token (savePaymentMethod's output — a single-use Paysafe.js token is rejected by the scheduler). Subscriptions attach to a PLAN: pass planId to bill from a host-managed plan (the input amount/currency/cadence must match it — the adapter verifies and rejects a mismatch rather than silently billing something else), or omit it and the adapter creates a dedicated open-ended plan (numberOfCycles 0 = infinite) from the input inline.

      Idempotency: merchantRefNum is the scheduler's dedupe field ("unique for this accountId") and doubles as the lookup key, so input.merchantRefNum wins when supplied — passing it transfers the idempotency duty to it — and idempotencyKey fills it otherwise. A replayed create, or one whose answer was lost, recovers the existing subscription by that refNum instead of failing; neither POST is re-sent after a timeout or 5xx. The inline PLAN has no refNum channel, so a creation retried after a lost answer can leave an orphan plan behind; the subscription itself stays exactly-once, so no double billing can result.

      pspCustomerId and metadata have no scheduler channel and are withheld: the customer profile derives from the vaulted token, and the subscription object carries no metadata field.

      Returns Promise<NativeSubscriptionRecord>

    • Paysafe refunds settle against a settlement, not the payment — resolved here so callers keep one API. The settlement is the first with money left that findSettlements finds: a settle-with-auth payment's, or a full capture's. A partial capture's settlement, under the capture's own key, cannot be found from the payment, so it is not refunded here, and nor is a capture an earlier release settled under its key. A SEPA or Bacs payment is refused once the payment read shows its type, before anything else is sent: Paysafe refunds neither rail.

      Parameters

      Returns Promise<RefundResult>

    • Polls an async refund to a terminal state — sandbox refunds in particular sit PENDING until the overnight settlement batch runs.

      A refund that states no currencyCode is reported as it comes: Paysafe does not require one (its card refund example carries none), and a refund names no payment or settlement to read the currency from.

      Parameters

      • refundId: string

      Returns Promise<RefundInfo>

    • "Test connection" probe: one side-effect-free read against the Customer Vault — look up an all-but-certainly-absent profile. This endpoint is an object-or-404 point lookup, so authentication is settled BEFORE the resource is resolved: only 401/403 means bad credentials, while every other status — a 2xx match, the expected 404 "no such profile", or any business 4xx — proves the credentials authenticated. Classified so a host UI can tell a wrong key (auth) from a transient outage (network). It is a single call, never retried (an auth rejection must not be replayed), and the credentials never leak into the result.

      Returns Promise<VerifyCredentialsResult>

    • Webhook handling — same adapter, separate concerns. Both async: future PSPs may need remote key retrieval; the contract stays uniform. MUST operate on the RAW request body bytes/string — re-serializing a parsed body breaks signatures (the conformance suite tests this).

      Parameters

      • rawBody: string
      • headers: Record<string, string>

      Returns Promise<boolean>