SDK Version: PayPal JS SDK v6 Framework: React 19.2.5 + TypeScript Frontend Package: @paypal/react-paypal-js v10.1.0 Backend Package: @paypal/paypal-server-sdk v2.1.0 Payment Methods: PayPal, Venmo, Pay Later, Guest Card, Subscriptions, Save, Credit, Apple Pay, Google Pay Demo: Multi-page checkout flows with routing
This React sample application demonstrates how to integrate different PayPal payment flows using PayPal's React component library, react-paypal-js.
Try the deployed example without setting up locally:
This demo runs in PayPal sandbox mode - use Sandbox test accounts to complete transactions.
Browse all available examples at the Examples Index.
- PayPal
- Venmo
- Pay Later
- PayPal Basic Card (guest card)
- PayPal Advanced Card (Card Fields)
- PayPal Subscriptions
- PayPal Save (vault without purchase)
- PayPal Credit
- Apple Pay
- Google Pay
| Technology | Version | Purpose |
|---|---|---|
| React | 19.2.5 | UI framework |
| Vite | 8.0.8 | Development server and bundler |
| TypeScript | 6.0.2 | Type safety |
| React Router DOM | 7.14.0 | Client-side routing |
| @paypal/react-paypal-js | 10.1.0 | React hooks and Context provider for PayPal V6 SDK |
| @paypal/paypal-server-sdk | 2.1.0 | Server-side PayPal API calls |
| react-error-boundary | 6.1.1 | Error boundary component for React |
- Node.js - Version 20.19+ (required by Vite 8)
- PayPal Developer Account - Required for sandbox credentials
- Environment Configuration - See the root README for instructions on setting up your
.envfile withPAYPAL_SANDBOX_CLIENT_IDandPAYPAL_SANDBOX_CLIENT_SECRET
This sample requires two servers running concurrently: the Node.js backend API and the React frontend.
Terminal 1 - Start the backend server:
cd server/node
npm install
npm startTerminal 2 - Start the React application:
cd client/prebuiltPages/react
npm install
npm start- Frontend: http://localhost:3000
- Backend: http://localhost:8080
The Vite dev server proxies /paypal-api requests to the backend server on port 8080.
Run the app and open the Home page (/) — it links to every flow. To read the code, browse
client/prebuiltPages/react/src/: the per-flow checkout wrappers that leverage the react-paypal-js package live in
src/paymentFlowCheckoutPages/, routing and SDK setup in src/App.tsx.
PayPalProvider from @paypal/react-paypal-js handles loading the PayPal V6 SDK scripts automatically. When mounted, it:
- Loads the core SDK script from PayPal's CDN
- Loads the component scripts specified in the
componentsprop - Creates an SDK instance with the provided
clientId - Makes the SDK available to child components via React Context
// src/App.tsx
<PayPalProvider
clientId={clientId}
components={[
"paypal-payments",
"venmo-payments",
"paypal-guest-payments",
"paypal-subscriptions",
"card-fields",
"paypal-messages",
"applepay-payments",
"googlepay-payments",
]}
pageType="checkout"
>
<RouterProvider router={router} />
</PayPalProvider>The components prop specifies which payment methods and features to load:
paypal-payments- PayPal and Pay Later buttonsvenmo-payments- Venmo buttonpaypal-guest-payments- Guest card payment buttonpaypal-subscriptions- Subscription buttonscard-fields- Card Fields (advanced card payment UI)paypal-messages- PayPal Messages promotional componentapplepay-payments- Apple Pay button and one-time payment session supportgooglepay-payments- Google Pay button and one-time payment session support
The Apple Pay demo requires:
- Safari on a supported Apple device
- HTTPS origin (Apple Pay is blocked on insecure origins)
- Apple Pay merchant/domain setup for the testing domain
- Apple Pay JS loaded in
index.html
<script
crossorigin
src="https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js"
></script>The Google Pay demo requires:
- Chrome or another modern browser that supports the Google Pay API
- Google Pay JS loaded in
index.html(must execute before the React bundle sowindow.google.payments.apiis available whenuseGooglePayOneTimePaymentSessionmounts)
<script defer src="https://pay.google.com/gp/p/js/pay.js"></script>Each checkout page uses useEligibleMethods to fetch eligibility data with the appropriate paymentFlow parameter.
| Hook | Environment | Use in this example? | Description |
|---|---|---|---|
useEligibleMethods |
Client-side | Yes | Returns { eligiblePaymentMethods, isLoading, error }. Fetches via SDK if context is empty, otherwise returns eligibility from the provider context. |
useFetchEligibleMethods |
Server-only | No | Requires "server-only" import. Do not use in client-side React apps. |
useEligibleMethods returns eligiblePaymentMethods, whose isEligible(...) gates buttons that are
not universally available (e.g. Pay Later, Credit). Always-available buttons (PayPal, Venmo, Guest)
render unconditionally.
// OneTimePaymentCheckout.tsx
const { error: eligibilityError, eligiblePaymentMethods } = useEligibleMethods({
payload: {
currencyCode: "USD",
paymentFlow: "ONE_TIME_PAYMENT",
},
});
if (eligibilityError) {
return <div>Failed to load eligible payment methods.</div>;
}
const isPayLaterEligible = eligiblePaymentMethods?.isEligible("paylater");
return (
<>
<PayPalOneTimePaymentButton {...props} />
{isPayLaterEligible && <PayLaterOneTimePaymentButton {...props} />}
</>
);See src/paymentFlowCheckoutPages/OneTimePaymentCheckout.tsx for the full implementation.
Uses VAULT_WITH_PAYMENT as the paymentFlow value to save the payment method and charge in one
transaction. See src/paymentFlowCheckoutPages/VaultWithPurchaseCheckout.tsx.
The paypal-messages component renders promotional messaging. See
src/paypalMessages/PayPalMessages.tsx (component) and src/paypalMessages/PayPalMessagesDemo.tsx
(demo page, route /paypal-messages).
Each payment button uses a specialized hook to create a payment session:
| Hook | Button Type |
|---|---|
usePayPalOneTimePaymentSession |
PayPal |
useVenmoOneTimePaymentSession |
Venmo |
usePayLaterOneTimePaymentSession |
Pay Later |
useApplePayOneTimePaymentSession |
Apple Pay |
useGooglePayOneTimePaymentSession |
Google Pay |
usePayPalGuestPaymentSession |
Basic Card |
usePayPalSubscriptionPaymentSession |
Subscriptions |
usePayPalSavePaymentSession |
Save Payment Method |
usePayPalCreditOneTimePaymentSession |
Credit (One-time) |
usePayPalCreditSavePaymentSession |
Credit (Save) |
Example Usage:
import {
usePayPalOneTimePaymentSession,
type UsePayPalOneTimePaymentSessionProps,
} from "@paypal/react-paypal-js/sdk-v6";
const PayPalButton = (props: UsePayPalOneTimePaymentSessionProps) => {
const { handleClick } = usePayPalOneTimePaymentSession(props);
return (
<paypal-button type="pay" onClick={() => handleClick()}></paypal-button>
);
};Card Fields provides specialized hooks to create payment sessions that work seamlessly with individual card field components:
| Hook | Use Case |
|---|---|
usePayPalCardFieldsOneTimePaymentSession |
One-time payment |
usePayPalCardFieldsSavePaymentSession |
Save payment method |
Example Usage:
import {
PayPalCardNumberField,
PayPalCardExpiryField,
PayPalCardCvvField,
usePayPalCardFieldsOneTimePaymentSession,
} from "@paypal/react-paypal-js/sdk-v6";
import { useEffect } from "react";
const CardFieldsPayment = () => {
const { submit, submitResponse } = usePayPalCardFieldsOneTimePaymentSession();
const handleCreateOrder = async () => {
return await createOrder();
};
const handleSubmit = async () => {
const { orderId } = await handleCreateOrder();
await submit(orderId);
};
useEffect(() => {
if (!submitResponse) {
return;
}
const { orderId, state } = submitResponse.data;
switch (state) {
case "succeeded":
captureOrder({ orderId });
break;
case "failed":
console.error(
`One time payment failed: orderId: ${orderId}, message: ${message}`,
);
break;
}
}, [submitResponse]);
return (
<>
<PayPalCardNumberField placeholder="Enter card number" />
<PayPalCardExpiryField placeholder="MM/YY" />
<PayPalCardCvvField placeholder="Enter CVV" />
<button onClick={handleSubmit}>Pay</button>
</>
);
};The Node.js backend handles sensitive PayPal API interactions.
Location: server/node/
Package: @paypal/paypal-server-sdk v2.1.0
SDK Controllers:
| Controller | Purpose |
|---|---|
OAuthAuthorizationController |
Generate browser-safe client tokens |
OrdersController |
Create and capture orders |
SubscriptionsController |
Create subscriptions and billing plans |
VaultController |
Store payment methods (save without purchase) |
Key Files:
| File | Purpose |
|---|---|
src/server.ts |
Express server entry point and route definitions |
src/paypalServerSdk.ts |
PayPal SDK client configuration |
| Endpoint | Method | Description |
|---|---|---|
/paypal-api/auth/browser-safe-client-id |
GET | Fetches client ID for SDK |
/paypal-api/products |
GET | Returns product pricing (SKU → price mapping) |
/paypal-api/checkout/orders/create-order-for-one-time-payment |
POST | Creates a PayPal order for one-time payment |
/paypal-api/checkout/orders/{orderId}/capture |
POST | Captures the approved payment |
/paypal-api/vault/create-setup-token-for-paypal-save-payment |
POST | Creates vault setup token for saving payment info |
/paypal-api/vault/create-payment-token/{vaultSetupToken} |
POST | Creates long-lived payment token from setup token |
/paypal-api/billing/create-subscription |
POST | Creates a subscription |