PayPal JS SDK Libraries

repository·main·Indexed 43 days ago

https://github.com/paypal/paypal-js

A collection of JavaScript and React libraries designed to simplify integration with the PayPal JS SDK. Includes @paypal/paypal-js for SDK loading and TypeScript definitions, and @paypal/react-paypal-js for React components. Supports legacy V5 loading via loadScript() and the modern V6 component-based architecture via loadCoreSdkScript() and PayPalProvider.

Tokens
91.4K
Snippets
199
Records
281
Agent score
55%

What's inside PayPal JS

  1. Overview of @paypal/react-paypal-js (v6)

    main

    The @paypal/react-paypal-js package is a React wrapper for the PayPal v6 Web SDK. It provides interactive React components for implementing PayPal checkout flows, including Buttons, Card Fields, and Braintree integrations.

    This Storybook instance serves as an interactive reference where you can manipulate component controls to see live, editable examples of how the components re-render.

  2. Available PayPal JS packages

    main

    The PayPal JS monorepo provides several libraries for integrating with the PayPal JS SDK depending on your environment:

    • @paypal/paypal-js: The core Vanilla JS loader and TypeScript types.
    • @paypal/react-paypal-js: The official React library for PayPal integration.
    • @paypal/react-paypal-js-storybook: Storybook documentation and components for the React library.
  3. Understand the create → approve → capture flow

    main

    A standard payment integration follows a three-step lifecycle where the client-side SDK coordinates with your server:

    1. Create: The button's createOrder callback triggers a call to your server's order creation endpoint. Your server calls PayPal, receives an orderId, and returns it to the client.
    2. Approve: The buyer interacts with the PayPal or wallet UI to approve the transaction. This step is handled entirely by the SDK.
    3. Capture: Once approved, the button's onApprove callback receives the orderId. The client forwards this orderId to your server's capture endpoint. Your server then calls PayPal to finalize the payment and returns the status (e.g., status: "COMPLETED").

    Crucial Security Rule: The client should only forward the orderId to your server; it must never attempt to create or capture orders directly.

  4. Supported Payment Methods in react-paypal-js

    main

    The library supports a wide range of payment methods through the PayPal JS SDK V6, including:

    • PayPal: Standard PayPal checkout
    • Venmo: Venmo payments
    • Pay Later: PayPal's buy now, pay later option
    • PayPal Basic Card: Guest card payments without a PayPal account
    • PayPal Advanced Card: Card payments with enhanced features and customization options
    • PayPal Subscriptions: Recurring billing subscriptions
    • PayPal Save: Vault payment methods without purchase
    • PayPal Credit: PayPal Credit one-time and save payments
    • Google Pay: Native Google Pay button flow through PaymentsClient
    • Apple Pay: Native Apple Pay payments (Safari + HTTPS only)
    • Braintree PayPal: PayPal checkout for Braintree merchants via the paypalCheckoutV6 module
  5. Integrate Local Payment Methods (LPMs) with react-paypal-js

    main

    The @paypal/react-paypal-js/sdk-v6 entry provides components and hooks for over 45 regional Local Payment Methods (e.g., iDEAL, Bancontact, BLIK, Pix, Klarna).

    Integration Patterns

    Every LPM provides three primary integration points:

    1. <MethodName>OneTimePaymentButton: A self-contained component that renders both required buyer fields (like full name) and the payment button.
    2. use<MethodName>OneTimePaymentSession: A hook for full control over the click handler, pending/error states, and custom button UI.
    3. <MethodName>PaymentButton: A standalone button that reads its session from context, useful when required fields need to be laid out separately from the button.

    Important Constraints

    • Presentation Mode: LPMs only support presentationMode="popup". Other modes like "auto" or "modal" are not supported and will cause type errors.
    • Dynamic Selection: If you need to select an LPM dynamically (e.g., via an lpm string), use the generic exports: LPMOneTimePaymentButton, useLPMOneTimePaymentSession, LPM_REGISTRY, and LPMName.
    import {
      PayPalProvider,
      IdealOneTimePaymentButton,
    } from "@paypal/react-paypal-js/sdk-v6";
    
    // ... createOrder and onApprove logic ...
    
    export default function App() {
      return (
        <PayPalProvider
          clientId="YOUR_CLIENT_ID"
          environment="sandbox"
          components={["ideal-payments"]}
          pageType="checkout"
        >
          <IdealOneTimePaymentButton
            presentationMode="popup"
            createOrder={createOrder}
            onApprove={onApprove}
            onCancel={() => console.log("Payment cancelled")}
          />
        </PayPalProvider>
      );
    }
  6. Use Payment Session hooks for advanced control

    main

    For advanced use cases requiring full control over the payment flow (e.g., using custom web components), use the session hooks directly.

    Note on Configuration: One-time payment session hooks (like usePayPalOneTimePaymentSession) accept either a static orderId or a createOrder callback. These are mutually exclusive. Use orderId if the order is already created, or createOrder to defer creation until the user clicks the button.

    | Hook | Payment Type |
    | -------------------------------------- | ------------------- |
    | `usePayPalOneTimePaymentSession` | PayPal |
    | `useVenmoOneTimePaymentSession` | Venmo |
    | `usePayLaterOneTimePaymentSession` | Pay Later |
    | `usePayPalGuestPaymentSession` | Basic Card |
    | `usePayPalSubscriptionPaymentSession` | Subscriptions |
    | `usePayPalSavePaymentSession` | Save Payment Method |
    | `usePayPalCreditOneTimePaymentSession` | Credit (One-time) |
    | `usePayPalCreditSavePaymentSession` | Credit (Save) |
    | `useGooglePayOneTimePaymentSession` | Google Pay |
    | `useApplePayOneTimePaymentSession` | Apple Pay |
  7. How react-paypal-js works

    main

    The react-paypal-js library is composed of two main parts that work together using React's Context API:

    1. Context Provider: The <PayPalScriptProvider /> component manages the loading of the PayPal JS SDK script. It should be added to the root of your React application. It handles state management and supports reloading the script when configuration parameters change.
    2. SDK Components: Components like <PayPalButtons />, <PayPalHostedField />, or <PayPalCardFieldsForm /> are used to render the actual UI for PayPal products served by the JS SDK.

    This architecture ensures that the SDK is loaded once and its state is shared across all UI components.

    import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js";
    
    export default function App() {
      return (
        <PayPalScriptProvider options={{ clientId: "test" }}>
          <PayPalButtons style={{ layout: "horizontal" }} />
        </PayPalScriptProvider>
      );
    }
  8. How react-paypal-js works with the PayPal JS SDK V5

    main

    The react-paypal-js library provides React components that abstract the complexities of loading the PayPal JS SDK. Instead of manually managing <script> tags in an index.html file, which can lead to sub-optimal loading in Single Page Applications (SPAs), this library enforces best practices such as:

    • Async Loading: Enforces loading the JS SDK upfront so components render immediately when needed.
    • Global Configuration: Uses a provider pattern to manage the SDK lifecycle.
    • Dynamic Reloading: Supports dispatching actions to reload the JS SDK and re-render components when global parameters (like currency) change.
    • Component-Based Architecture: Provides dedicated components for different PayPal and Braintree offerings, ensuring script loading is decoupled from rendering.
  9. How the PayPal v6 checkout flow works

    main

    A complete checkout process involves three tiers: the React application (client), your backend server, and PayPal. The React components are designed to be secure by never handling secret keys or payment amounts directly; these responsibilities remain on your server.

    The 4-Step Lifecycle

    1. Load: Use PayPalProvider to fetch a browser-safe clientId (or client token) from your server. This loads the SDK once and provides a single checkout-scoped instance.
    2. Eligibility: Use the useEligibleMethods() hook to query your server's find-eligible-methods endpoint. This determines which payment methods (e.g., Apple Pay, Google Pay, PayPal) should be rendered based on the buyer, merchant, and amount.
    3. Create order: When a user clicks a payment button, the component's createOrder callback triggers a call to your server. Your server then calls PayPal's Orders API to generate an orderId.
    4. Capture: Once the buyer approves the transaction, the onApprove callback triggers a call to your server to capture the order via the PayPal Orders API.

    Note: Steps 3 and 4 are intentionally server-side to ensure security and integrity.

  10. Choose between Client Token and Client ID authentication

    main

    The SDK supports two browser-safe authentication methods. Choose based on your feature requirements:

    • Client token: A short-lived token fetched from your server (e.g., via a browser-safe-client-token endpoint). This is the recommended approach as it unlocks every SDK feature.
    • Client ID: A static, public identifier. While simpler to implement, it only works with a limited set of features.

    When in doubt, use the client token to ensure full compatibility with all SDK methods.

  11. Avoid redundant fetches by not mixing payloads with hydration

    main

    When using hydration (Path B), do not pass a payload to the useEligibleMethods() hook in your client components.

    The Problem: The hydrated response is stored without a payload. If you call useEligibleMethods({ payload }) in a child, the hook will look for data matching that specific payload, fail to find it in the hydrated state, and trigger a redundant client-side fetch.

    The Solution:

    • If Hydrating: Call useEligibleMethods() with no payload. Include any necessary amount/currency data in the server-side fetchEligibleMethods call instead.
    • If Not Hydrating: Call useEligibleMethods({ payload }) and let it fetch on the client.