-
Notifications
You must be signed in to change notification settings - Fork 16
Feat: Adds Bank ACH Onetime payment examples #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ItsYou
wants to merge
13
commits into
paypal-examples:main
Choose a base branch
from
ItsYou:feature/bank-ach-one-time-payment
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
6eb3285
Adds Bank ACH One-time Payment sample
79ef602
cleanup ACH vault sample data
398a588
Update README:
16ef936
docs: update Bank ACH one-time payment README
cd9ab72
Merge branch 'main' into feature/bank-ach-one-time-payment
ItsYou c80943a
remove apiCode and countryCode from eligibleMethods request payload
3c136ed
remove payment methods from eligibility call
f8e4324
Adds orderAmount to eligibility payload
1172997
add styling for order amount input
55f9cc0
rename directory, remove merchantID input
274de60
direct merchant sample - remove merchantID
45d56e9
remove unused style rules
d8530f5
update readme to remove merchantID
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| # Bank ACH One-time Payment Sample Integration | ||
|
|
||
| This is a demo of how to integration Bank ACH One-time payment via PayPal Web SDK v6. Paypal SDK lets merchants provide Bank ACH as a payment method via plain HTML and javascript. | ||
|
|
||
| ## ️Architecture Overview | ||
|
|
||
| This sample demonstrates a complete Bank ACH integration flow: | ||
|
|
||
| 1. Initialize PayPal Web SDK with Bank ACH component with a sample order creation. | ||
| 2. Opens popup for payer bank authentication and account selection when Bank ACH button is clicked. | ||
| 3. OnSuccess callback passed to SDK initialization captures order with returned order ID. | ||
|
|
||
| ### Server Setup | ||
|
|
||
| 1. **Navigate to the server directory:** | ||
|
|
||
| ```bash | ||
| cd server/node | ||
| ``` | ||
|
|
||
| 2. **Install dependencies:** | ||
|
|
||
| ```bash | ||
| npm install | ||
| ``` | ||
|
|
||
| 3. **Configure environment variables:** | ||
| Create a `.env` file in the root directory: | ||
|
|
||
| ```env | ||
| PAYPAL_SANDBOX_CLIENT_ID=your_paypal_sandbox_client_id | ||
| PAYPAL_SANDBOX_CLIENT_SECRET=your_paypal_sandbox_client_secret | ||
| ``` | ||
|
|
||
| 4. **Start the server:** | ||
| ```bash | ||
| npm start | ||
| ``` | ||
| The server will run on `https://localhost:8080` | ||
|
|
||
| ### Client Setup | ||
|
|
||
| 1. **Navigate to the Bank ACH One Time Payment demo directory:** | ||
|
|
||
| ```bash | ||
| cd client/components/bank/oneTimePayment/html | ||
| ``` | ||
|
|
||
| 2. **Install dependencies:** | ||
|
|
||
| ```bash | ||
| npm install | ||
| ``` | ||
|
|
||
| 3. **Start the development server:** | ||
| ```bash | ||
| npm start | ||
| ``` | ||
| The demo will be available at `http://localhost:3000` | ||
|
|
||
|
|
||
| ## 🧪 Testing the Integration | ||
|
|
||
| 1. **Visit http://localhost:3000** | ||
| - Enter your Merchant ID | ||
| - Click the Bank Payment button | ||
| - The bank login popup will be displayed | ||
|
|
||
| 3. **Complete bank login and account selection** | ||
| - Enter your credentials to get authenticated | ||
| - Select the bank and account you would like to use for testing | ||
|
|
||
| 4. **Verify Results** | ||
| - Check the browser console logs for order capture details | ||
| - Check Event Logs -> API Calls at [developer.paypal.com](https://developer.paypal.com) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "name": "v6-web-sdk-sample-integration-client-html", | ||
| "version": "1.0.0", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "build": "vite build", | ||
| "preview": "vite preview", | ||
| "start": "vite", | ||
| "format": "prettier . --write", | ||
| "format:check": "prettier . --check", | ||
| "lint": "echo \"eslint is not set up\"" | ||
| }, | ||
| "license": "Apache-2.0", | ||
| "devDependencies": { | ||
| "prettier": "^3.6.2", | ||
| "vite": "^7.0.4" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| const getMerchantId = () => { | ||
| return document.getElementById('merchant-id-input').value || "7NU2UD5KWFN6U" // placeholder value. only for SB testing | ||
| } | ||
|
|
||
| const getOrderAmount = () => { | ||
| return document.getElementById('order-amount-input').value || "100.00" | ||
| } | ||
|
|
||
| const orderPayload = { | ||
| intent: 'CAPTURE', | ||
| purchaseUnits: [ | ||
| { | ||
| amount: { | ||
| currencyCode: "USD", | ||
| value: getOrderAmount(), | ||
| }, | ||
| payee: { | ||
| merchantId: getMerchantId() | ||
| } | ||
| }, | ||
| ] | ||
| } | ||
|
|
||
| async function onPayPalWebSdkLoaded() { | ||
| try { | ||
| const clientToken = await getBrowserSafeClientToken(); | ||
| const sdkInstance = await window.paypal.createInstance({ | ||
| clientToken, | ||
| components: ["bank-ach-payments"], | ||
| pageType: "checkout", | ||
| }); | ||
|
|
||
| const paymentMethods = await sdkInstance.findEligibleMethods({ | ||
| currencyCode: "USD", | ||
| paymentFlow: "ONE_TIME_PAYMENT", | ||
| merchantId: getMerchantId(), | ||
| amount: getOrderAmount() | ||
| }); | ||
|
|
||
| if (paymentMethods.isEligible("ach")) { | ||
| setupAchButton(sdkInstance); | ||
| } | ||
| console.log('sdk loaded') | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| } | ||
|
|
||
| const paymentSessionOptions = { | ||
| async onApprove(data) { | ||
| console.log("onApprove", data); | ||
| const orderData = await captureOrder({ | ||
| orderId: data.orderId, | ||
| }); | ||
| console.log("Capture order", orderData); | ||
| }, | ||
| onCancel(data) { | ||
| console.log("onCancel", data); | ||
| }, | ||
| onError(error) { | ||
| console.log("onError", error); | ||
| }, | ||
| }; | ||
|
|
||
|
|
||
| async function setupAchButton(sdkInstance) { | ||
| const achPaymentSession = sdkInstance.createBankAchOneTimePaymentSession( | ||
| paymentSessionOptions, | ||
| ); | ||
| document.getElementById('ach-button-container').innerHTML = '<bank-ach-button id="ach-button">'; | ||
| const onClick = async () => { | ||
| const startOptions = { | ||
| presentationMode: "popup", | ||
| } | ||
|
|
||
| const checkoutOptionsPromise = createOrder(orderPayload).then((orderId) => { | ||
| console.log("Created order", orderId); | ||
| return orderId | ||
| }); | ||
| try { | ||
| await achPaymentSession.start(startOptions, checkoutOptionsPromise) | ||
| } catch(e) { | ||
| console.error(e) | ||
| } | ||
| } | ||
| const achButton = document.querySelector("#ach-button"); | ||
|
|
||
| achButton.removeAttribute("hidden"); | ||
| achButton.addEventListener("click", onClick); | ||
| } | ||
|
|
||
| async function getBrowserSafeClientToken() { | ||
| const response = await fetch("/paypal-api/auth/browser-safe-client-token", { | ||
| method: "GET", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| }, | ||
| }); | ||
| const { accessToken } = await response.json(); | ||
|
|
||
| return accessToken; | ||
| } | ||
|
|
||
| async function createOrder(orderPayload) { | ||
| const response = await fetch("/paypal-api/checkout/orders/create", { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| }, | ||
| body: JSON.stringify(orderPayload), | ||
| }); | ||
| const { id } = await response.json(); | ||
|
|
||
| return {orderId: id}; | ||
| } | ||
|
|
||
|
|
||
| async function captureOrder({ orderId }) { | ||
| const response = await fetch( | ||
| `/paypal-api/checkout/orders/${orderId}/capture`, | ||
| { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| }, | ||
| }, | ||
| ); | ||
| const data = await response.json(); | ||
|
|
||
| return data; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||
| <!doctype html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
| <meta charset="UTF-8" /> | ||||
| <title>One-Time Payment - Recommended Integration - PayPal Web SDK</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||||
| <style> | ||||
| #ach-button-container { | ||||
| display: flex; | ||||
| flex-direction: column; | ||||
| gap: 12px; | ||||
| } | ||||
| #merchant-id-input { | ||||
| margin-top: 12px; | ||||
| padding: 8px; | ||||
| font-size: 16px; | ||||
| width: 300px; | ||||
| } | ||||
| #order-amount-input { | ||||
| margin-top: 12px; | ||||
| padding: 8px; | ||||
| font-size: 16px; | ||||
| width: 300px; | ||||
| } | ||||
| </style> | ||||
| </head> | ||||
| <body> | ||||
| <h1>One-Time Payment Recommended Integration</h1> | ||||
|
|
||||
| <div id="ach-button-container"> | ||||
| <button id="ach-button" hidden>Pay with Bank Account</button> | ||||
| </div> | ||||
|
|
||||
| <label for="merchant-id-input">Merchant ID:</label> | ||||
| <input type="text" id="merchant-id-input" placeholder="Enter your merchant ID" /> | ||||
|
||||
| <input type="text" id="merchant-id-input" placeholder="Enter your merchant ID" /> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { defineConfig } from "vite"; | ||
|
|
||
| // https://vitejs.dev/config/ | ||
| export default defineConfig(() => { | ||
| return { | ||
| plugins: [], | ||
| root: "src", | ||
| server: { | ||
| port: 3000, | ||
| proxy: { | ||
| "/paypal-api": { | ||
| target: "http://localhost:8080", | ||
| changeOrigin: true, | ||
| secure: false, | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.