PayFanout API reference
    Preparing search index...

    Interface ServerConformanceFixtures

    The contract every ServerPaymentAdapter — present or future — must pass. This is what makes "extensible" verifiable rather than aspirational: a new PSP ships by writing an adapter package that passes this suite, with zero changes to core or to consuming applications.

    interface ServerConformanceFixtures {
        completePayment?: {
            input(session: PaymentSession): CompletePaymentInput;
        };
        failingCalls: {
            expectedCode?: UnifiedErrorCode;
            name: string;
            invoke(adapter: ServerPaymentAdapter): Promise<unknown>;
        }[];
        idempotency?: {
            run(
                adapter: ServerPaymentAdapter,
                key: string,
            ): Promise<[unknown, unknown]>;
            sideEffectCount(): number;
        };
        money?: {
            expectations?: { idRoundTrip?: boolean; metadataEcho?: boolean };
            authorizedPayment?(
                adapter: ServerPaymentAdapter,
                input: { amount: number },
            ): Promise<string>;
            cancelablePayment?(adapter: ServerPaymentAdapter): Promise<string>;
            completedPayment?(
                adapter: ServerPaymentAdapter,
                input: { amount: number; id: string; metadata: Record<string, string> },
            ): Promise<string>;
        };
        onboarding?: AdapterOnboardingDescriptor;
        vault?: {
            clientToken?(): string | Promise<string>;
            storedToken?(
                adapter: ServerPaymentAdapter,
                pspCustomerId: string,
            ): Promise<string>;
        };
        webhook: {
            expectedAmount?: number;
            expectedEventId: string;
            expectedType: | "unknown"
            | "payment.succeeded"
            | "payment.failed"
            | "payment.requires_action"
            | "payment.processing"
            | "payment.refunded"
            | "payment.refund_failed"
            | "payment.canceled"
            | "payment.chargeback"
            | "payment.chargeback_won"
            | "payment.chargeback_lost";
            unknownEvent?: { headers: Record<string, string>; rawBody: string };
            validHeaders: Record<string, string>;
            validRawBody: string;
        };
        createSessionInput(): CreatePaymentSessionInput;
        threeDecimalSessionInput?(): CreatePaymentSessionInput;
        zeroDecimalSessionInput?(): CreatePaymentSessionInput;
    }
    Index
    completePayment?: { input(session: PaymentSession): CompletePaymentInput }

    Required when the adapter reports requiresServerCompletion.

    failingCalls: {
        expectedCode?: UnifiedErrorCode;
        name: string;
        invoke(adapter: ServerPaymentAdapter): Promise<unknown>;
    }[]

    Failure paths — each must reject with PayFanoutError, raw PSP error preserved.

    idempotency?: {
        run(
            adapter: ServerPaymentAdapter,
            key: string,
        ): Promise<[unknown, unknown]>;
        sideEffectCount(): number;
    }

    Idempotency-replay: same key twice -> same result, exactly one side effect.

    money?: {
        expectations?: { idRoundTrip?: boolean; metadataEcho?: boolean };
        authorizedPayment?(
            adapter: ServerPaymentAdapter,
            input: { amount: number },
        ): Promise<string>;
        cancelablePayment?(adapter: ServerPaymentAdapter): Promise<string>;
        completedPayment?(
            adapter: ServerPaymentAdapter,
            input: { amount: number; id: string; metadata: Record<string, string> },
        ): Promise<string>;
    }

    Money-path fixtures against the adapter's fake backend. REQUIRED — refunds, capture, and cancel are where broken adapters cost real money, so they are proven at the contract level, not left to per-adapter discipline: completedPayment whenever supportsRefunds, authorizedPayment whenever supportsManualCapture, cancelablePayment always (every PSP has a pre-completion state).

    Type Declaration

    • Optionalexpectations?: { idRoundTrip?: boolean; metadataEcho?: boolean }

      Honesty flags for documented PSP limitations (default true): set idRoundTrip false when the PSP has no field to carry the host id, metadataEcho false when metadata cannot be read back on retrieve.

    • authorizedPayment?: function
    • cancelablePayment?: function
    • completedPayment?: function
      • Creates a COMPLETED payment (money moved) of input.amount, carrying the host input.id and input.metadata; resolves its pspPaymentId.

        Parameters

        • adapter: ServerPaymentAdapter
        • input: { amount: number; id: string; metadata: Record<string, string> }

        Returns Promise<string>

    The adapter's exported onboarding descriptor. When provided, the suite asserts it is well-formed and consistent with the adapter (pspName match, credential fields, webhook events, CSP hosts) via validateOnboardingDescriptor.

    vault?: {
        clientToken?(): string | Promise<string>;
        storedToken?(
            adapter: ServerPaymentAdapter,
            pspCustomerId: string,
        ): Promise<string>;
    }

    Required when the adapter reports supportsSavedPaymentMethods: drives the vault round-trip (create customer -> save -> list -> charge twice -> delete).

    Type Declaration

    • clientToken?: function
      • Fresh single-use clientToken for savePaymentMethod (tokenize-first PSPs).

        Returns string | Promise<string>

    • storedToken?: function
      • Confirm-on-client PSPs (no savePaymentMethod method): given a customer id, produce a stored token by whatever save-during-checkout simulation the fake supports.

        Parameters

        Returns Promise<string>

    webhook: {
        expectedAmount?: number;
        expectedEventId: string;
        expectedType:
            | "unknown"
            | "payment.succeeded"
            | "payment.failed"
            | "payment.requires_action"
            | "payment.processing"
            | "payment.refunded"
            | "payment.refund_failed"
            | "payment.canceled"
            | "payment.chargeback"
            | "payment.chargeback_won"
            | "payment.chargeback_lost";
        unknownEvent?: { headers: Record<string, string>; rawBody: string };
        validHeaders: Record<string, string>;
        validRawBody: string;
    }

    Type Declaration

    • OptionalexpectedAmount?: number

      Asserted against the parsed event's normalized amount, when the payload carries one.

    • expectedEventId: string
    • expectedType:
          | "unknown"
          | "payment.succeeded"
          | "payment.failed"
          | "payment.requires_action"
          | "payment.processing"
          | "payment.refunded"
          | "payment.refund_failed"
          | "payment.canceled"
          | "payment.chargeback"
          | "payment.chargeback_won"
          | "payment.chargeback_lost"
    • OptionalunknownEvent?: { headers: Record<string, string>; rawBody: string }

      A correctly SIGNED delivery of an event type the adapter does not recognize.

    • validHeaders: Record<string, string>
    • validRawBody: string

      Exact raw body bytes as the PSP would send them, signature-matching validHeaders.