diff --git a/advanced-integration/public/app.js b/advanced-integration/client/app.js
similarity index 100%
rename from advanced-integration/public/app.js
rename to advanced-integration/client/app.js
diff --git a/advanced-integration/package.json b/advanced-integration/package.json
index 424f853e..1d8d34ed 100644
--- a/advanced-integration/package.json
+++ b/advanced-integration/package.json
@@ -2,11 +2,12 @@
"name": "paypal-advanced-integration",
"description": "Sample Node.js web app to integrate PayPal Advanced Checkout for online payments",
"version": "1.0.0",
- "main": "server.js",
+ "main": "server/server.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
- "start": "node server.js"
+ "start": "node server/server.js",
+ "format": "npx prettier --write **.js"
},
"license": "Apache-2.0",
"dependencies": {
diff --git a/advanced-integration/server.js b/advanced-integration/server/server.js
similarity index 98%
rename from advanced-integration/server.js
rename to advanced-integration/server/server.js
index becdb6a2..a7d84407 100644
--- a/advanced-integration/server.js
+++ b/advanced-integration/server/server.js
@@ -1,13 +1,13 @@
import express from "express";
import fetch from "node-fetch";
import "dotenv/config";
-import path from "path";
const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8888 } = process.env;
const base = "https://api-m.sandbox.paypal.com";
const app = express();
app.set("view engine", "ejs");
-app.use(express.static("public"));
+app.set("views", "./server/views");
+app.use(express.static("client"));
// parse post params sent in body in json format
app.use(express.json());
diff --git a/advanced-integration/views/checkout.ejs b/advanced-integration/server/views/checkout.ejs
similarity index 100%
rename from advanced-integration/views/checkout.ejs
rename to advanced-integration/server/views/checkout.ejs
diff --git a/standard-integration/README.md b/standard-integration/README.md
index c1c22ad8..c0bf83f3 100644
--- a/standard-integration/README.md
+++ b/standard-integration/README.md
@@ -6,7 +6,7 @@ This folder contains example code for a Standard PayPal integration using both t
1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create)
2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`
-3. Replace `test` in `index.html` with your app's client-id
+3. Replace `test` in `client/index.html` with your app's client-id
4. Run `npm install`
5. Run `npm start`
6. Open http://localhost:8888
diff --git a/standard-integration/client/app.js b/standard-integration/client/app.js
new file mode 100644
index 00000000..af056c7d
--- /dev/null
+++ b/standard-integration/client/app.js
@@ -0,0 +1,94 @@
+window.paypal
+ .Buttons({
+ createOrder: async () => {
+ try {
+ const response = await fetch("/api/orders", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ // use the "body" param to optionally pass additional order information
+ // like product ids and quantities
+ body: JSON.stringify({
+ cart: [
+ {
+ id: "YOUR_PRODUCT_ID",
+ quantity: "YOUR_PRODUCT_QUANTITY",
+ },
+ ],
+ }),
+ });
+
+ const orderData = await response.json();
+
+ if (orderData.id) {
+ return orderData.id;
+ } else {
+ const errorDetail = orderData?.details?.[0];
+ const errorMessage = errorDetail
+ ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})`
+ : JSON.stringify(orderData);
+
+ throw new Error(errorMessage);
+ }
+ } catch (error) {
+ console.error(error);
+ resultMessage(`Could not initiate PayPal Checkout...
${error}`);
+ }
+ },
+ onApprove: async (data, actions) => {
+ try {
+ const response = await fetch(`/api/orders/${data.orderID}/capture`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+
+ const orderData = await response.json();
+ // Three cases to handle:
+ // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
+ // (2) Other non-recoverable errors -> Show a failure message
+ // (3) Successful transaction -> Show confirmation or thank you message
+
+ const errorDetail = orderData?.details?.[0];
+
+ if (errorDetail?.issue === "INSTRUMENT_DECLINED") {
+ // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
+ // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/
+ return actions.restart();
+ } else if (errorDetail) {
+ // (2) Other non-recoverable errors -> Show a failure message
+ throw new Error(`${errorDetail.description} (${orderData.debug_id})`);
+ } else if (!orderData.purchase_units) {
+ throw new Error(JSON.stringify(orderData));
+ } else {
+ // (3) Successful transaction -> Show confirmation or thank you message
+ // Or go to another URL: actions.redirect('thank_you.html');
+ const transaction =
+ orderData?.purchase_units?.[0]?.payments?.captures?.[0] ||
+ orderData?.purchase_units?.[0]?.payments?.authorizations?.[0];
+ resultMessage(
+ `Transaction ${transaction.status}: ${transaction.id}
See console for all available details`,
+ );
+ console.log(
+ "Capture result",
+ orderData,
+ JSON.stringify(orderData, null, 2),
+ );
+ }
+ } catch (error) {
+ console.error(error);
+ resultMessage(
+ `Sorry, your transaction could not be processed...
${error}`,
+ );
+ }
+ },
+ })
+ .render("#paypal-button-container");
+
+// Example function to show a result to the user. Your site's UI library can be used instead.
+function resultMessage(message) {
+ const container = document.querySelector("#result-message");
+ container.innerHTML = message;
+}
diff --git a/standard-integration/client/checkout.html b/standard-integration/client/checkout.html
new file mode 100644
index 00000000..7b959c2f
--- /dev/null
+++ b/standard-integration/client/checkout.html
@@ -0,0 +1,15 @@
+
+
+