diff --git a/.devcontainer/advanced-integration/devcontainer.json b/.devcontainer/advanced-integration-v1/devcontainer.json
similarity index 84%
rename from .devcontainer/advanced-integration/devcontainer.json
rename to .devcontainer/advanced-integration-v1/devcontainer.json
index 2e840f6f..9ce61d30 100644
--- a/.devcontainer/advanced-integration/devcontainer.json
+++ b/.devcontainer/advanced-integration-v1/devcontainer.json
@@ -1,10 +1,10 @@
// For more details, see https://aka.ms/devcontainer.json.
{
- "name": "PayPal Advanced Integration",
+ "name": "advanced-integration-v1",
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
- "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/v1",
// Use 'onCreateCommand' to run commands when creating the container.
- "onCreateCommand": "bash ../.devcontainer/advanced-integration/welcome-message.sh",
+ "onCreateCommand": "bash ../../.devcontainer/advanced-integration-v1/welcome-message.sh",
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm install",
// Use 'postAttachCommand' to run commands when attaching to the container.
@@ -31,10 +31,10 @@
},
"customizations": {
"vscode": {
- "extensions": ["vsls-contrib.codetour"],
+ "extensions": ["vsls-contrib.codetour","PayPal.vscode-paypal"],
"settings": {
"git.openRepositoryInParentFolders": "always"
}
}
}
-}
+}
\ No newline at end of file
diff --git a/.devcontainer/advanced-integration/welcome-message.sh b/.devcontainer/advanced-integration-v1/welcome-message.sh
similarity index 100%
rename from .devcontainer/advanced-integration/welcome-message.sh
rename to .devcontainer/advanced-integration-v1/welcome-message.sh
diff --git a/.devcontainer/advanced-integration-v2-html-dotnet/devcontainer.json b/.devcontainer/advanced-integration-v2-html-dotnet/devcontainer.json
new file mode 100644
index 00000000..2ef1ead0
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-html-dotnet/devcontainer.json
@@ -0,0 +1,56 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "advanced-integration-v2/html/dotnet",
+ "image": "mcr.microsoft.com/devcontainers/dotnet:8.0",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/advanced-integration-v2-html-dotnet/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Advanced Checkout Flow"
+ },
+ "3000": {
+ "label": "HTML",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "dotnet",
+ "VISIBLE_FOLDER_CLIENT": "html",
+ "VISIBLE_FOLDER_PROJECT": "advanced-integration",
+ "VISIBLE_FOLDER_VERSION": "v2"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "ms-dotnettools.csharp"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
diff --git a/.devcontainer/advanced-integration-v2-html-dotnet/welcome-message.sh b/.devcontainer/advanced-integration-v2-html-dotnet/welcome-message.sh
new file mode 100644
index 00000000..ae9a72f9
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-html-dotnet/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/advanced-integration-v2-html-java/devcontainer.json b/.devcontainer/advanced-integration-v2-html-java/devcontainer.json
new file mode 100644
index 00000000..3dcae617
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-html-java/devcontainer.json
@@ -0,0 +1,57 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "advanced-integration-v2/html/java",
+ "image": "mcr.microsoft.com/devcontainers/java:21",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/advanced-integration-v2-html-java/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Advanced Checkout Flow"
+ },
+ "3000": {
+ "label": "HTML",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "java",
+ "VISIBLE_FOLDER_CLIENT": "html",
+ "VISIBLE_FOLDER_PROJECT": "advanced-integration",
+ "VISIBLE_FOLDER_VERSION": "v2"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": ["vsls-contrib.codetour", "PayPal.vscode-paypal"],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/java:1": {
+ "version": "22",
+ "jdkDistro": "tem",
+ "installMaven": "true"
+ },
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/advanced-integration-v2-html-java/welcome-message.sh b/.devcontainer/advanced-integration-v2-html-java/welcome-message.sh
new file mode 100644
index 00000000..ae9a72f9
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-html-java/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/advanced-integration-v2-html-node/devcontainer.json b/.devcontainer/advanced-integration-v2-html-node/devcontainer.json
new file mode 100644
index 00000000..f5f00400
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-html-node/devcontainer.json
@@ -0,0 +1,56 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "advanced-integration-v2/html/node",
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:20",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/advanced-integration-v2-html-node/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Advanced Checkout Flow"
+ },
+ "3000": {
+ "label": "HTML",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "node",
+ "VISIBLE_FOLDER_CLIENT": "html",
+ "VISIBLE_FOLDER_PROJECT": "advanced-integration",
+ "VISIBLE_FOLDER_VERSION": "v2"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "dbaeumer.vscode-eslint"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
diff --git a/.devcontainer/advanced-integration-v2-html-node/welcome-message.sh b/.devcontainer/advanced-integration-v2-html-node/welcome-message.sh
new file mode 100644
index 00000000..ae9a72f9
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-html-node/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/advanced-integration-v2-html-php/devcontainer.json b/.devcontainer/advanced-integration-v2-html-php/devcontainer.json
new file mode 100644
index 00000000..6afcc17b
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-html-php/devcontainer.json
@@ -0,0 +1,56 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "advanced-integration-v2/html/php",
+ "image": "mcr.microsoft.com/devcontainers/php:8",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/advanced-integration-v2-html-php/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Advanced Checkout Flow"
+ },
+ "3000": {
+ "label": "HTML",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "php",
+ "VISIBLE_FOLDER_CLIENT": "html",
+ "VISIBLE_FOLDER_PROJECT": "advanced-integration",
+ "VISIBLE_FOLDER_VERSION": "v2"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "xdebug.php-debug"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/advanced-integration-v2-html-php/welcome-message.sh b/.devcontainer/advanced-integration-v2-html-php/welcome-message.sh
new file mode 100644
index 00000000..ae9a72f9
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-html-php/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/advanced-integration-v2-react-dotnet/devcontainer.json b/.devcontainer/advanced-integration-v2-react-dotnet/devcontainer.json
new file mode 100644
index 00000000..a4911ab0
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-react-dotnet/devcontainer.json
@@ -0,0 +1,56 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": " advanced-integration-v2/react/dotnet",
+ "image": "mcr.microsoft.com/devcontainers/dotnet:8.0",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Advanced Checkout Flow"
+ },
+ "3000": {
+ "label": "React",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "dotnet",
+ "VISIBLE_FOLDER_CLIENT": "react",
+ "VISIBLE_FOLDER_PROJECT": "advanced-integration",
+ "VISIBLE_FOLDER_VERSION": "v2"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "ms-dotnettools.csharp"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
diff --git a/.devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh b/.devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh
new file mode 100644
index 00000000..ae9a72f9
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/advanced-integration-v2-react-java/devcontainer.json b/.devcontainer/advanced-integration-v2-react-java/devcontainer.json
new file mode 100644
index 00000000..e55feb54
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-react-java/devcontainer.json
@@ -0,0 +1,57 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "advanced-integration-v2/react/java",
+ "image": "mcr.microsoft.com/devcontainers/java:21",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/advanced-integration-v2-react-java/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Advanced Checkout Flow"
+ },
+ "3000": {
+ "label": "React",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "java",
+ "VISIBLE_FOLDER_CLIENT": "react",
+ "VISIBLE_FOLDER_PROJECT": "advanced-integration",
+ "VISIBLE_FOLDER_VERSION": "v2"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": ["vsls-contrib.codetour", "PayPal.vscode-paypal"],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/java:1": {
+ "version": "22",
+ "jdkDistro": "tem",
+ "installMaven": "true"
+ },
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/advanced-integration-v2-react-java/welcome-message.sh b/.devcontainer/advanced-integration-v2-react-java/welcome-message.sh
new file mode 100644
index 00000000..ae9a72f9
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-react-java/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/advanced-integration-v2-react-node/devcontainer.json b/.devcontainer/advanced-integration-v2-react-node/devcontainer.json
new file mode 100644
index 00000000..2efab718
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-react-node/devcontainer.json
@@ -0,0 +1,56 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "advanced-integration-v2/react/node",
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:20",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/advanced-integration-v2-react-node/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Advanced Checkout Flow"
+ },
+ "3000": {
+ "label": "React",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "node",
+ "VISIBLE_FOLDER_CLIENT": "react",
+ "VISIBLE_FOLDER_PROJECT": "advanced-integration",
+ "VISIBLE_FOLDER_VERSION": "v2"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "dbaeumer.vscode-eslint"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
diff --git a/.devcontainer/advanced-integration-v2-react-node/welcome-message.sh b/.devcontainer/advanced-integration-v2-react-node/welcome-message.sh
new file mode 100644
index 00000000..ae9a72f9
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-react-node/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/advanced-integration-v2-react-php/devcontainer.json b/.devcontainer/advanced-integration-v2-react-php/devcontainer.json
new file mode 100644
index 00000000..4980fd30
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-react-php/devcontainer.json
@@ -0,0 +1,56 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "advanced-integration-v2/react/php",
+ "image": "mcr.microsoft.com/devcontainers/php:8",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/advanced-integration-v2-react-php/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Advanced Checkout Flow"
+ },
+ "3000": {
+ "label": "React",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "php",
+ "VISIBLE_FOLDER_CLIENT": "react",
+ "VISIBLE_FOLDER_PROJECT": "advanced-integration",
+ "VISIBLE_FOLDER_VERSION": "v2"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "xdebug.php-debug"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/advanced-integration-v2-react-php/welcome-message.sh b/.devcontainer/advanced-integration-v2-react-php/welcome-message.sh
new file mode 100644
index 00000000..ae9a72f9
--- /dev/null
+++ b/.devcontainer/advanced-integration-v2-react-php/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Advanced Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/post-commands.sh b/.devcontainer/post-commands.sh
new file mode 100755
index 00000000..505bdf50
--- /dev/null
+++ b/.devcontainer/post-commands.sh
@@ -0,0 +1,104 @@
+#!/bin/bash
+
+set -e
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+WORKSPACE_DIR="$( cd "$SCRIPT_DIR/.." &> /dev/null && pwd )"
+
+VISIBLE_FOLDER_SERVER="${VISIBLE_FOLDER_SERVER}"
+VISIBLE_FOLDER_CLIENT="${VISIBLE_FOLDER_CLIENT}"
+VISIBLE_FOLDER_PROJECT="${VISIBLE_FOLDER_PROJECT}"
+VISIBLE_FOLDER_VERSION="${VISIBLE_FOLDER_VERSION}"
+
+# Set up SERVER_DIR & CLIENT_DIR
+if [ -z "$VISIBLE_FOLDER_VERSION" ]; then
+ SERVER_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/server"
+ CLIENT_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/client/${VISIBLE_FOLDER_CLIENT}"
+else
+ SERVER_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/${VISIBLE_FOLDER_VERSION}/server"
+ CLIENT_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/${VISIBLE_FOLDER_VERSION}/client/${VISIBLE_FOLDER_CLIENT}"
+fi
+
+# Backend setup functions
+setup_backend() {
+ case "$VISIBLE_FOLDER_SERVER" in
+ node)
+ cd "$SERVER_DIR/node" && npm install
+ ;;
+ java)
+ cd "$SERVER_DIR" && cd java && mvn clean install
+ ;;
+ dotnet)
+ cd "$SERVER_DIR/dotnet" && dotnet restore
+ ;;
+ php)
+ cd "$SERVER_DIR" && cd php && composer install
+ ;;
+ *)
+ echo "Unknown server: $VISIBLE_FOLDER_SERVER"
+ exit 1
+ ;;
+ esac
+}
+
+# Frontend setup functions
+setup_frontend() {
+ cd "$CLIENT_DIR" && npm install
+}
+
+# Backend start functions
+start_backend() {
+ case "$VISIBLE_FOLDER_SERVER" in
+ node)
+ cd "$SERVER_DIR/node" && npm start
+ ;;
+ java)
+ cd "$SERVER_DIR/java" && mvn spring-boot:run
+ ;;
+ dotnet)
+ cd "$SERVER_DIR/dotnet" && dotnet run
+ ;;
+ php)
+ cd "$SERVER_DIR/php" && composer start
+ ;;
+ *)
+ echo "Unknown server: $VISIBLE_FOLDER_SERVER"
+ exit 1
+ ;;
+ esac
+}
+
+# Frontend start functions
+start_frontend() {
+ cd "$CLIENT_DIR" && npm run start --no-analytics
+}
+
+# Post-create commands
+post_create() {
+ echo "Running post-create commands..."
+ setup_backend
+ setup_frontend
+}
+
+# Post-attach commands
+post_attach() {
+ echo "Running post-attach commands..."
+ start_backend &
+ start_frontend
+}
+
+# Main execution
+case "$1" in
+ post-create)
+ post_create
+ ;;
+ post-attach)
+ post_attach
+ ;;
+ *)
+ echo "Usage: $0 {post-create|post-attach}"
+ exit 1
+ ;;
+esac
+
+exit 0
\ No newline at end of file
diff --git a/.devcontainer/standard-integration/devcontainer.json b/.devcontainer/save-payment-method/devcontainer.json
similarity index 82%
rename from .devcontainer/standard-integration/devcontainer.json
rename to .devcontainer/save-payment-method/devcontainer.json
index 846dd982..88b05faa 100644
--- a/.devcontainer/standard-integration/devcontainer.json
+++ b/.devcontainer/save-payment-method/devcontainer.json
@@ -1,10 +1,10 @@
// For more details, see https://aka.ms/devcontainer.json.
{
- "name": "PayPal Standard Integration",
+ "name": "save-payment-metthod",
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
- "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/standard-integration",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/save-payment-method",
// Use 'onCreateCommand' to run commands when creating the container.
- "onCreateCommand": "bash ../.devcontainer/standard-integration/welcome-message.sh",
+ "onCreateCommand": "bash ../.devcontainer/save-payment-method/welcome-message.sh",
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm install",
// Use 'postAttachCommand' to run commands when attaching to the container.
@@ -15,7 +15,7 @@
"forwardPorts": [8888],
"portsAttributes": {
"8888": {
- "label": "Preview of Standard Checkout Flow",
+ "label": "Preview of Save Payment Method Flow",
"onAutoForward": "openBrowserOnce"
}
},
@@ -31,10 +31,10 @@
},
"customizations": {
"vscode": {
- "extensions": ["vsls-contrib.codetour"],
+ "extensions": ["vsls-contrib.codetour","PayPal.vscode-paypal"],
"settings": {
"git.openRepositoryInParentFolders": "always"
}
}
}
-}
+}
\ No newline at end of file
diff --git a/.devcontainer/save-payment-method/welcome-message.sh b/.devcontainer/save-payment-method/welcome-message.sh
new file mode 100644
index 00000000..7ed0d59c
--- /dev/null
+++ b/.devcontainer/save-payment-method/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Save Payment Method Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Save Payment Method Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
\ No newline at end of file
diff --git a/.devcontainer/standard-integration-html-dotnet/devcontainer.json b/.devcontainer/standard-integration-html-dotnet/devcontainer.json
new file mode 100644
index 00000000..810ffa39
--- /dev/null
+++ b/.devcontainer/standard-integration-html-dotnet/devcontainer.json
@@ -0,0 +1,55 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "standard-integration/html/dotnet",
+ "image": "mcr.microsoft.com/devcontainers/dotnet:8.0",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/standard-integration-html-dotnet/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Standard Checkout Flow"
+ },
+ "3000": {
+ "label": "HTML",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "dotnet",
+ "VISIBLE_FOLDER_CLIENT": "html",
+ "VISIBLE_FOLDER_PROJECT": "standard-integration"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "ms-dotnettools.csharp"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
diff --git a/.devcontainer/standard-integration/welcome-message.sh b/.devcontainer/standard-integration-html-dotnet/welcome-message.sh
similarity index 100%
rename from .devcontainer/standard-integration/welcome-message.sh
rename to .devcontainer/standard-integration-html-dotnet/welcome-message.sh
diff --git a/.devcontainer/standard-integration-html-java/devcontainer.json b/.devcontainer/standard-integration-html-java/devcontainer.json
new file mode 100644
index 00000000..88f7280a
--- /dev/null
+++ b/.devcontainer/standard-integration-html-java/devcontainer.json
@@ -0,0 +1,56 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "standard-integration/html/java",
+ "image": "mcr.microsoft.com/devcontainers/java:21",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/standard-integration-html-java/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Standard Checkout Flow"
+ },
+ "3000": {
+ "label": "Html",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "java",
+ "VISIBLE_FOLDER_CLIENT": "html",
+ "VISIBLE_FOLDER_PROJECT": "standard-integration"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": ["vsls-contrib.codetour", "PayPal.vscode-paypal"],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/java:1": {
+ "version": "22",
+ "jdkDistro": "tem",
+ "installMaven": "true"
+ },
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/standard-integration-html-java/welcome-message.sh b/.devcontainer/standard-integration-html-java/welcome-message.sh
new file mode 100644
index 00000000..78cce216
--- /dev/null
+++ b/.devcontainer/standard-integration-html-java/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/standard-integration-html-node/devcontainer.json b/.devcontainer/standard-integration-html-node/devcontainer.json
new file mode 100644
index 00000000..beaa4863
--- /dev/null
+++ b/.devcontainer/standard-integration-html-node/devcontainer.json
@@ -0,0 +1,55 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "standard-integration/html/node",
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:20",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/standard-integration-html-node/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Standard Checkout Flow"
+ },
+ "3000": {
+ "label": "HTML",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "node",
+ "VISIBLE_FOLDER_CLIENT": "html",
+ "VISIBLE_FOLDER_PROJECT": "standard-integration"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "dbaeumer.vscode-eslint"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
diff --git a/.devcontainer/standard-integration-html-node/welcome-message.sh b/.devcontainer/standard-integration-html-node/welcome-message.sh
new file mode 100644
index 00000000..78cce216
--- /dev/null
+++ b/.devcontainer/standard-integration-html-node/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/standard-integration-html-php/devcontainer.json b/.devcontainer/standard-integration-html-php/devcontainer.json
new file mode 100644
index 00000000..fc60c8f7
--- /dev/null
+++ b/.devcontainer/standard-integration-html-php/devcontainer.json
@@ -0,0 +1,55 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "standard-integration/html/php",
+ "image": "mcr.microsoft.com/devcontainers/php:8",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/standard-integration-html-php/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Standard Checkout Flow"
+ },
+ "3000": {
+ "label": "HTML",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "php",
+ "VISIBLE_FOLDER_CLIENT": "html",
+ "VISIBLE_FOLDER_PROJECT": "standard-integration"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "xdebug.php-debug"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/standard-integration-html-php/welcome-message.sh b/.devcontainer/standard-integration-html-php/welcome-message.sh
new file mode 100644
index 00000000..78cce216
--- /dev/null
+++ b/.devcontainer/standard-integration-html-php/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/standard-integration-react-dotnet/devcontainer.json b/.devcontainer/standard-integration-react-dotnet/devcontainer.json
new file mode 100644
index 00000000..d2a2e587
--- /dev/null
+++ b/.devcontainer/standard-integration-react-dotnet/devcontainer.json
@@ -0,0 +1,55 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "standard-integration/react/dotnet",
+ "image": "mcr.microsoft.com/devcontainers/dotnet:8.0",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/standard-integration-react-dotnet/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Standard Checkout Flow"
+ },
+ "3000": {
+ "label": "React",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "dotnet",
+ "VISIBLE_FOLDER_CLIENT": "react",
+ "VISIBLE_FOLDER_PROJECT": "standard-integration"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "ms-dotnettools.csharp"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
diff --git a/.devcontainer/standard-integration-react-dotnet/welcome-message.sh b/.devcontainer/standard-integration-react-dotnet/welcome-message.sh
new file mode 100644
index 00000000..78cce216
--- /dev/null
+++ b/.devcontainer/standard-integration-react-dotnet/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/standard-integration-react-java/devcontainer.json b/.devcontainer/standard-integration-react-java/devcontainer.json
new file mode 100644
index 00000000..d9f5d333
--- /dev/null
+++ b/.devcontainer/standard-integration-react-java/devcontainer.json
@@ -0,0 +1,56 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "standard-integration/react/java",
+ "image": "mcr.microsoft.com/devcontainers/java:21",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/standard-integration-react-java/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Standard Checkout Flow"
+ },
+ "3000": {
+ "label": "React",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "java",
+ "VISIBLE_FOLDER_CLIENT": "react",
+ "VISIBLE_FOLDER_PROJECT": "standard-integration"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": ["vsls-contrib.codetour", "PayPal.vscode-paypal"],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/java:1": {
+ "version": "22",
+ "jdkDistro": "tem",
+ "installMaven": "true"
+ },
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/standard-integration-react-java/welcome-message.sh b/.devcontainer/standard-integration-react-java/welcome-message.sh
new file mode 100644
index 00000000..78cce216
--- /dev/null
+++ b/.devcontainer/standard-integration-react-java/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/standard-integration-react-node/devcontainer.json b/.devcontainer/standard-integration-react-node/devcontainer.json
new file mode 100644
index 00000000..fa64ab68
--- /dev/null
+++ b/.devcontainer/standard-integration-react-node/devcontainer.json
@@ -0,0 +1,55 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "standard-integration/react/node",
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:20",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/standard-integration-react-node/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Standard Checkout Flow"
+ },
+ "3000": {
+ "label": "React",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "node",
+ "VISIBLE_FOLDER_CLIENT": "react",
+ "VISIBLE_FOLDER_PROJECT": "standard-integration"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "dbaeumer.vscode-eslint"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
diff --git a/.devcontainer/standard-integration-react-node/welcome-message.sh b/.devcontainer/standard-integration-react-node/welcome-message.sh
new file mode 100644
index 00000000..78cce216
--- /dev/null
+++ b/.devcontainer/standard-integration-react-node/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/standard-integration-react-php/devcontainer.json b/.devcontainer/standard-integration-react-php/devcontainer.json
new file mode 100644
index 00000000..e5bfcf12
--- /dev/null
+++ b/.devcontainer/standard-integration-react-php/devcontainer.json
@@ -0,0 +1,55 @@
+// For more details, see https://aka.ms/devcontainer.json.
+{
+ "name": "standard-integration/react/php",
+ "image": "mcr.microsoft.com/devcontainers/php:8",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ // Use 'onCreateCommand' to run commands when creating the container.
+ "onCreateCommand": "bash .devcontainer/standard-integration-react-php/welcome-message.sh",
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create",
+ // Use 'postAttachCommand' to run commands when attaching to the container.
+ "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach",
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [3000, 8080],
+ "portsAttributes": {
+ "8080": {
+ "label": "Preview of Standard Checkout Flow"
+ },
+ "3000": {
+ "label": "React",
+ "onAutoForward": "openBrowserOnce"
+ }
+ },
+ "secrets": {
+ "PAYPAL_CLIENT_ID": {
+ "description": "Sandbox client ID of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ },
+ "PAYPAL_CLIENT_SECRET": {
+ "description": "Sandbox secret of the application.",
+ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox"
+ }
+ },
+ "containerEnv": {
+ "VISIBLE_FOLDER_SERVER": "php",
+ "VISIBLE_FOLDER_CLIENT": "react",
+ "VISIBLE_FOLDER_PROJECT": "standard-integration"
+ },
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "vsls-contrib.codetour",
+ "PayPal.vscode-paypal",
+ "xdebug.php-debug"
+ ],
+ "settings": {
+ "git.openRepositoryInParentFolders": "always"
+ }
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "lts"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/standard-integration-react-php/welcome-message.sh b/.devcontainer/standard-integration-react-php/welcome-message.sh
new file mode 100644
index 00000000..78cce216
--- /dev/null
+++ b/.devcontainer/standard-integration-react-php/welcome-message.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted."
+
+ALTERNATE_WELCOME_MESSAGE="
+👋 Welcome to the \"PayPal Standard Checkout Integration Example\"
+
+🛠️ Your environment is fully setup with all the required software.
+
+🚀 The checkout page will automatically open in the browser after the server is started."
+
+if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then
+ WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}"
+fi
+
+sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt"
diff --git a/.devcontainer/update_settings.sh b/.devcontainer/update_settings.sh
new file mode 100755
index 00000000..736b30ff
--- /dev/null
+++ b/.devcontainer/update_settings.sh
@@ -0,0 +1,140 @@
+#!/bin/bash
+
+set -e
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+WORKSPACE_DIR="$( cd "$SCRIPT_DIR/.." &> /dev/null && pwd )"
+
+VISIBLE_FOLDER_SERVER="$VISIBLE_FOLDER_SERVER"
+VISIBLE_FOLDER_CLIENT="$VISIBLE_FOLDER_CLIENT"
+VISIBLE_FOLDER_PROJECT="$VISIBLE_FOLDER_PROJECT"
+VISIBLE_FOLDER_VERSION="$VISIBLE_FOLDER_VERSION"
+
+DEVCONTAINER_WORKSPACE="$WORKSPACE_DIR/.devcontainer"
+SETTINGS_FILE="$WORKSPACE_DIR/.vscode/settings.json"
+PROJECT_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT"
+
+
+if [ -z "$VISIBLE_FOLDER_CLIENT" ]; then
+ echo "Error: VISIBLE_FOLDER_CLIENT is not set, setting it to default"
+ VISIBLE_FOLDER_CLIENT="DEFAULT"
+fi
+
+if [ -z "$VISIBLE_FOLDER_VERSION" ]; then
+ SERVER_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT/server"
+ CLIENT_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT/client"
+ VERSION_WORKSPACE="$PROJECT_WORKSPACE"
+ VISIBLE_FOLDER_DEVCONTAINER="$VISIBLE_FOLDER_PROJECT-$VISIBLE_FOLDER_CLIENT-$VISIBLE_FOLDER_SERVER"
+ PROJECT_DIR="$VISIBLE_FOLDER_PROJECT"
+else
+ SERVER_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT/$VISIBLE_FOLDER_VERSION/server"
+ CLIENT_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT/$VISIBLE_FOLDER_VERSION/client"
+ VERSION_WORKSPACE="$PROJECT_WORKSPACE/$VISIBLE_FOLDER_VERSION"
+ VISIBLE_FOLDER_DEVCONTAINER="$VISIBLE_FOLDER_PROJECT-$VISIBLE_FOLDER_VERSION-$VISIBLE_FOLDER_CLIENT-$VISIBLE_FOLDER_SERVER"
+ PROJECT_DIR="$VISIBLE_FOLDER_PROJECT/$VISIBLE_FOLDER_VERSION"
+
+fi
+echo "SERVER_WORKSPACE:$SERVER_WORKSPACE"
+echo "CLIENT_WORKSPACE:$CLIENT_WORKSPACE"
+echo "VISIBLE_FOLDER_DEVCONTAINER:$VISIBLE_FOLDER_DEVCONTAINER"
+echo "PROJECT_WORKSPACE:$PROJECT_WORKSPACE"
+
+
+echo "Workspace directory: $WORKSPACE_DIR"
+echo "Server directory: $SERVER_WORKSPACE"
+echo "Visible server folder: $VISIBLE_FOLDER_SERVER"
+echo "Visible client folder: $VISIBLE_FOLDER_CLIENT"
+echo "Visible project folder: $VISIBLE_FOLDER_PROJECT"
+echo "Visible version: $VISIBLE_FOLDER_VERSION"
+echo "Visible devcontainer: $DEVCONTAINER_WORKSPACE"
+if [ ! -d "$SERVER_WORKSPACE" ]; then
+ echo "Error: Server directory not found at $SERVER_WORKSPACE"
+ exit 1
+fi
+
+if [ ! -d "$DEVCONTAINER_WORKSPACE" ]; then
+ echo "Error: .devcontainer directory not found at $DEVCONTAINER_WORKSPACE"
+ exit 1
+fi
+
+if [ -z "$VISIBLE_FOLDER_SERVER" ]; then
+ echo "Error: VISIBLE_FOLDER_SERVER is not set"
+ exit 1
+fi
+
+mkdir -p "$(dirname "$SETTINGS_FILE")"
+
+echo "{
+ \"files.exclude\": {" > "$SETTINGS_FILE"
+
+first=true
+
+for dir in "$WORKSPACE_DIR"/*/ ; do
+ dir_name=$(basename "$dir")
+ if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_PROJECT" ]; then
+ if [ "$first" = true ] ; then
+ first=false
+ else
+ echo "," >> "$SETTINGS_FILE"
+ fi
+ echo -n " \"**/$dir_name\": true" >> "$SETTINGS_FILE"
+ fi
+done
+
+if [ -n "$VISIBLE_FOLDER_VERSION" ]; then
+ for dir in "$PROJECT_WORKSPACE"/*/ ; do
+ dir_name=$(basename "$dir")
+ if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_VERSION" ]; then
+ if [ "$first" = true ] ; then
+ first=false
+ else
+ echo "," >> "$SETTINGS_FILE"
+ fi
+ echo -n " \"**/$VISIBLE_FOLDER_PROJECT/$dir_name\": true" >> "$SETTINGS_FILE"
+ fi
+ done
+fi
+
+for dir in "$DEVCONTAINER_WORKSPACE"/*/ ; do
+ dir_name=$(basename "$dir")
+ if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_DEVCONTAINER" ]; then
+ if [ "$first" = true ] ; then
+ first=false
+ else
+ echo "," >> "$SETTINGS_FILE"
+ fi
+ echo -n " \"**/.devcontainer/$dir_name\": true" >> "$SETTINGS_FILE"
+ fi
+done
+
+for dir in "$SERVER_WORKSPACE"/*/ ; do
+ dir_name=$(basename "$dir")
+ if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_SERVER" ]; then
+ if [ "$first" = true ] ; then
+ first=false
+ else
+ echo "," >> "$SETTINGS_FILE"
+ fi
+ echo -n " \"**/$PROJECT_DIR/server/$dir_name\": true" >> "$SETTINGS_FILE"
+ fi
+done
+
+for dir in "$CLIENT_WORKSPACE"/*/ ; do
+ dir_name=$(basename "$dir")
+ if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_CLIENT" ]; then
+ if [ "$first" = true ] ; then
+ first=false
+ else
+ echo "," >> "$SETTINGS_FILE"
+ fi
+ echo -n " \"**/$PROJECT_DIR/client/$dir_name\": true" >> "$SETTINGS_FILE"
+ fi
+done
+
+echo "
+ }
+}" >> "$SETTINGS_FILE"
+
+echo "VS Code settings updated to show only $VISIBLE_FOLDER_SERVER and $VISIBLE_FOLDER_CLIENT folder in server directory."
+echo "Contents of $SETTINGS_FILE:"
+cat "$SETTINGS_FILE"
\ No newline at end of file
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index ba842418..9ae8d9e3 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -29,7 +29,7 @@ jobs:
- name: 👕 Lint code with ESLint
run: >
- find . -name package.json -maxdepth 2 -type f | while read -r file; do
+ find . -name package.json -maxdepth 3 -type f | while read -r file; do
directory=$(dirname "$file")
cd "$directory" && npm run lint && cd -
done
diff --git a/.gitignore b/.gitignore
index 5f9a1890..c889f486 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,3 +99,13 @@ dist
# TernJS port file
.tern-port
+
+# dotnet
+*.sln
+
+# env
+*.local
+
+#Codespace
+.vscode/settings.json
+.devcontainer/update_settings.sh
diff --git a/README.md b/README.md
index e2f4e583..98fbede3 100644
--- a/README.md
+++ b/README.md
@@ -41,8 +41,33 @@ These examples will ask you to run commands like `npm install` and `npm start`.
You'll need a version of node >= 16 which can be downloaded from the [Node.js website](https://nodejs.org/en/download/).
-### PayPal Codespaces Links
+# Running on Codespaces
+Follow below steps to use Codespaces.
+
+1) Click "New with options..." to open a page where you can choose the Dev container to run.
+![image](https://github.com/user-attachments/assets/0d4bf202-0c94-42ec-aa2e-d8ccb6da9eb8)
+
+2) Choose the Dev container to run
+![image](https://github.com/user-attachments/assets/b612467d-9fdc-4666-8dfa-0d99af6a2d39)
+
+3) Client ID and Client Secrets are required for running the application in codespace.
+![image](https://github.com/user-attachments/assets/cbbc4521-aa43-403f-9243-e3c555e67f4a)
+
+
+### Link to codespaces
+
| Application | Codespaces Link |
| ---- | ---- |
-| Advanced Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration%2Fdevcontainer.json)|
-| Standard Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fstandard-integration%2Fdevcontainer.json)|
\ No newline at end of file
+| Advanced Integration v2 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration-v2%2Fdevcontainer.json)|
+| Advanced Integration v1 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration-v1%2Fdevcontainer.json)|
+| Standard Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fstandard-integration%2Fdevcontainer.json)|
+| Save Payment Method Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fsave-payment-method%2Fdevcontainer.json)|
+
+### Learn more
+
+You can read more about codespaces in the [PayPal Developer Docs](https://developer.paypal.com/api/rest/sandbox/codespaces).
+
+### Feedback
+
+* To report a bug or suggest a new feature, create an [issue in GitHub](https://github.com/paypal-examples/paypaldevsupport/issues/new/choose).
+* To submit feedback, go to [PayPal Developer Docs](https://developer.paypal.com/api/rest/sandbox/codespaces) and select the "Feedback" tab.
diff --git a/advanced-integration/README.md b/advanced-integration/README.md
index 923a5234..ef1dd69d 100644
--- a/advanced-integration/README.md
+++ b/advanced-integration/README.md
@@ -1,9 +1,14 @@
-# Advanced Integration Example
+# Advanced Checkout Integration Example
-This folder contains example code for an Advanced PayPal integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API.
+This folder contains example code for a PayPal advanced Checkout integration using both the JavaScript SDK and Node.js to complete transactions with the PayPal REST API.
+
+- [`v2`](v2/README.md) contains sample code for the current advanced Checkout integration. This includes guidance on using Card Fields.
+- [`v1`](v1/README.md) contains sample code for the legacy advanced Checkout integration. Use `v2` for new integrations.
## Instructions
+These instructions apply to the sample code for both `v2` and `v1`:
+
1. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`.
2. Run `npm install`
3. Run `npm start`
diff --git a/advanced-integration/.gitignore b/advanced-integration/v1/.gitignore
similarity index 100%
rename from advanced-integration/.gitignore
rename to advanced-integration/v1/.gitignore
diff --git a/advanced-integration/v1/README.md b/advanced-integration/v1/README.md
new file mode 100644
index 00000000..152ef9ae
--- /dev/null
+++ b/advanced-integration/v1/README.md
@@ -0,0 +1,14 @@
+# Advanced Integration Example
+
+This folder contains example code for [version 1](https://developer.paypal.com/docs/checkout/advanced/integrate/sdk/v1) of a PayPal advanced Checkout integration using the JavaScript SDK and Node.js to complete transactions with the PayPal REST API.
+
+> **Note:** Version 1 is a legacy integration. Use [version 2](https://developer.paypal.com/docs/checkout/advanced/integrate/) for new integrations.
+
+## Instructions
+
+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. Run `npm install`.
+4. Run `npm start`.
+5. Open http://localhost:8888.
+6. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator).
diff --git a/advanced-integration/client/app.js b/advanced-integration/v1/client/app.js
similarity index 100%
rename from advanced-integration/client/app.js
rename to advanced-integration/v1/client/app.js
diff --git a/advanced-integration/.env.example b/advanced-integration/v1/env.example
similarity index 100%
rename from advanced-integration/.env.example
rename to advanced-integration/v1/env.example
diff --git a/advanced-integration/package.json b/advanced-integration/v1/package.json
similarity index 88%
rename from advanced-integration/package.json
rename to advanced-integration/v1/package.json
index ff3f5b41..0e93024f 100644
--- a/advanced-integration/package.json
+++ b/advanced-integration/v1/package.json
@@ -9,7 +9,7 @@
"start": "nodemon server/server.js",
"format": "npx prettier --write **/*.{js,md}",
"format:check": "npx prettier --check **/*.{js,md}",
- "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser"
+ "lint": "npx eslint server/*.js client/*.js --no-config-lookup"
},
"license": "Apache-2.0",
"dependencies": {
diff --git a/advanced-integration/server/server.js b/advanced-integration/v1/server/server.js
similarity index 100%
rename from advanced-integration/server/server.js
rename to advanced-integration/v1/server/server.js
diff --git a/advanced-integration/server/views/checkout.ejs b/advanced-integration/v1/server/views/checkout.ejs
similarity index 100%
rename from advanced-integration/server/views/checkout.ejs
rename to advanced-integration/v1/server/views/checkout.ejs
diff --git a/advanced-integration/v1/views/checkout.ejs b/advanced-integration/v1/views/checkout.ejs
new file mode 100644
index 00000000..12522326
--- /dev/null
+++ b/advanced-integration/v1/views/checkout.ejs
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/advanced-integration/v2/client/html/.env.example b/advanced-integration/v2/client/html/.env.example
new file mode 100644
index 00000000..dbfed9bd
--- /dev/null
+++ b/advanced-integration/v2/client/html/.env.example
@@ -0,0 +1,4 @@
+# Create an application to obtain credentials at
+# https://developer.paypal.com/dashboard/applications/sandbox
+
+PAYPAL_CLIENT_ID=YOUR_CLIENT_ID_GOES_HERE
diff --git a/advanced-integration/v2/client/html/.gitignore b/advanced-integration/v2/client/html/.gitignore
new file mode 100644
index 00000000..ed648a05
--- /dev/null
+++ b/advanced-integration/v2/client/html/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+*.local
\ No newline at end of file
diff --git a/advanced-integration/v2/client/html/README.md b/advanced-integration/v2/client/html/README.md
new file mode 100644
index 00000000..08187da8
--- /dev/null
+++ b/advanced-integration/v2/client/html/README.md
@@ -0,0 +1,74 @@
+# Advanced Integration with PayPal : HTML/JS
+
+## Getting Started
+
+This guide will walk you through setting up and running the HTML/JS Advanced Integration locally.
+
+### Before You Code
+
+1. **Setup a PayPal Account**
+
+ To get started, you'll need a developer, personal, or business account.
+
+ [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer)
+
+ You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts.
+
+2. **Create an Application**
+
+ Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create).
+
+### Installation
+
+```bash
+npm install
+```
+
+### Configuration
+
+1. Environmental Variables (.env)
+
+ - Rename the .env.example file to .env
+ - Update the following keys with their actual values -
+
+ ```bash
+ PAYPAL_CLIENT_ID=
+ ```
+
+2. Connecting the client and server (vite.config.js)
+
+ - Open vite.config.js in the root directory.
+ - Locate the proxy configuration object.
+ - Update the proxy key to match the server's address and port. For example:
+
+ ```js
+ export default defineConfig({
+
+ server: {
+ proxy: {
+ "/api": {
+ target: "http://localhost:8080", // Replace with your server URL
+ changeOrigin: true,
+ },
+ },
+ },
+ });
+ ```
+
+3. Starting the development server
+
+ - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory.
+
+ - **Start the client**:
+
+ ```bash
+ npm run start
+ ```
+
+ This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output).
+
+### Additional Notes
+
+- **Server Setup**: Make sure you have the server up and running before starting the client.
+- **Environment Variables**: Carefully configure the environment variables in the .env file to match your setup.
+- **Proxy Configuration**: The proxy setting in vite.config.js is crucial for routing API requests from the client to the server during development.
diff --git a/advanced-integration/v2/client/html/package.json b/advanced-integration/v2/client/html/package.json
new file mode 100644
index 00000000..c14f152f
--- /dev/null
+++ b/advanced-integration/v2/client/html/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "paypal-advanced-integration-frontend-html",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "vite build",
+ "preview": "vite preview",
+ "start": "vite",
+ "format": "npx prettier --write **/*.{js,md}",
+ "format:check": "npx prettier --check **/*.{js,md}"
+ },
+ "devDependencies": {
+ "dotenv": "^16.4.5",
+ "vite": "^5.4.2"
+ }
+}
diff --git a/advanced-integration/v2/client/html/src/app.js b/advanced-integration/v2/client/html/src/app.js
new file mode 100644
index 00000000..02cd182a
--- /dev/null
+++ b/advanced-integration/v2/client/html/src/app.js
@@ -0,0 +1,167 @@
+async function createOrderCallback() {
+ 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}`);
+ }
+ }
+
+ async function onApproveCallback(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 transaction =
+ orderData?.purchase_units?.[0]?.payments?.captures?.[0] ||
+ orderData?.purchase_units?.[0]?.payments?.authorizations?.[0];
+ const errorDetail = orderData?.details?.[0];
+
+ // this actions.restart() behavior only applies to the Buttons component
+ if (errorDetail?.issue === "INSTRUMENT_DECLINED" && !data.card && actions) {
+ // (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 ||
+ !transaction ||
+ transaction.status === "DECLINED"
+ ) {
+ // (2) Other non-recoverable errors -> Show a failure message
+ let errorMessage;
+ if (transaction) {
+ errorMessage = `Transaction ${transaction.status}: ${transaction.id}`;
+ } else if (errorDetail) {
+ errorMessage = `${errorDetail.description} (${orderData.debug_id})`;
+ } else {
+ errorMessage = JSON.stringify(orderData);
+ }
+
+ throw new Error(errorMessage);
+ } else {
+ // (3) Successful transaction -> Show confirmation or thank you message
+ // Or go to another URL: actions.redirect('thank_you.html');
+ 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...
;
+};
diff --git a/advanced-integration/v2/client/react/src/index.html b/advanced-integration/v2/client/react/src/index.html
new file mode 100644
index 00000000..4330e684
--- /dev/null
+++ b/advanced-integration/v2/client/react/src/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+ React PayPal JS SDK Advanced Integration
+
+
+
+
+
+
+
diff --git a/advanced-integration/v2/client/react/src/main.jsx b/advanced-integration/v2/client/react/src/main.jsx
new file mode 100644
index 00000000..569fdf2f
--- /dev/null
+++ b/advanced-integration/v2/client/react/src/main.jsx
@@ -0,0 +1,9 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App.jsx";
+
+ReactDOM.createRoot(document.getElementById("root")).render(
+
+
+
+);
diff --git a/advanced-integration/v2/client/react/vite.config.js b/advanced-integration/v2/client/react/vite.config.js
new file mode 100644
index 00000000..274f8cf5
--- /dev/null
+++ b/advanced-integration/v2/client/react/vite.config.js
@@ -0,0 +1,20 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ root: "src",
+ envDir: "../",
+ envPrefix: "PAYPAL",
+ server: {
+ port: 3000,
+ proxy: {
+ "/api": {
+ target: "http://localhost:8080",
+ changeOrigin: true,
+ secure: false,
+ },
+ },
+ },
+})
\ No newline at end of file
diff --git a/advanced-integration/v2/server/dotnet/.gitignore b/advanced-integration/v2/server/dotnet/.gitignore
new file mode 100644
index 00000000..cbbd0b5c
--- /dev/null
+++ b/advanced-integration/v2/server/dotnet/.gitignore
@@ -0,0 +1,2 @@
+bin/
+obj/
\ No newline at end of file
diff --git a/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj b/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj
new file mode 100644
index 00000000..838e3aa4
--- /dev/null
+++ b/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj
@@ -0,0 +1,12 @@
+
+
+
+ net8.0
+ PayPalAdvancedIntegration
+
+
+
+
+
+
+
diff --git a/advanced-integration/v2/server/dotnet/README.md b/advanced-integration/v2/server/dotnet/README.md
new file mode 100644
index 00000000..6170999e
--- /dev/null
+++ b/advanced-integration/v2/server/dotnet/README.md
@@ -0,0 +1,35 @@
+# Advanced Integration .NET Sample
+
+PayPal Advanced Integration sample in .NET
+
+## Running the sample
+
+1. **Add your API credentials to the environment:**
+
+ - **Windows (powershell)**
+
+ ```powershell
+ $env:PAYPAL_CLIENT_ID = ""
+ $env:PAYPAL_CLIENT_SECRET = ""
+ ```
+
+ - **Linux / MacOS**
+
+ ```bash
+ export PAYPAL_CLIENT_ID=""
+ export PAYPAL_CLIENT_SECRET=""
+ ```
+
+2. **Build the server**
+
+ ```bash
+ dotnet restore
+ ```
+
+3. **Run the server**
+
+ ```bash
+ dotnet run
+ ```
+
+4. Go to [http://localhost:8080/](http://localhost:8080/)
diff --git a/advanced-integration/v2/server/dotnet/Server.cs b/advanced-integration/v2/server/dotnet/Server.cs
new file mode 100644
index 00000000..5132e726
--- /dev/null
+++ b/advanced-integration/v2/server/dotnet/Server.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using PaypalServerSDK.Standard;
+using PaypalServerSDK.Standard.Authentication;
+using PaypalServerSDK.Standard.Controllers;
+using PaypalServerSDK.Standard.Http.Response;
+using PaypalServerSDK.Standard.Models;
+using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;
+
+namespace PayPalAdvancedIntegration;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseUrls("http://localhost:8080");
+ webBuilder.UseStartup();
+ });
+}
+
+public class Startup
+{
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddMvc().AddNewtonsoftJson();
+ services.AddHttpClient();
+ }
+
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+ app.UseRouting();
+ app.UseStaticFiles();
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ });
+ }
+}
+
+[ApiController]
+public class CheckoutController : Controller
+{
+ private readonly OrdersController _ordersController;
+ private readonly PaymentsController _paymentsController;
+
+ private IConfiguration _configuration { get; }
+ private string _paypalClientId
+ {
+ get { return System.Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); }
+ }
+ private string _paypalClientSecret
+ {
+ get { return System.Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); }
+ }
+
+ private readonly ILogger _logger;
+
+ public CheckoutController(IConfiguration configuration, ILogger logger)
+ {
+ _configuration = configuration;
+ _logger = logger;
+
+ // Initialize the PayPal SDK client
+ PaypalServerSDKClient client = new PaypalServerSDKClient.Builder()
+ .Environment(PaypalServerSDK.Standard.Environment.Sandbox)
+ .ClientCredentialsAuth(
+ new ClientCredentialsAuthModel.Builder(_paypalClientId, _paypalClientSecret).Build()
+ )
+ .LoggingConfig(config =>
+ config
+ .LogLevel(LogLevel.Information)
+ .RequestConfig(reqConfig => reqConfig.Body(true))
+ .ResponseConfig(respConfig => respConfig.Headers(true))
+ )
+ .Build();
+
+ _ordersController = client.OrdersController;
+ _paymentsController = client.PaymentsController;
+ }
+
+ [HttpPost("api/orders")]
+ public async Task CreateOrder([FromBody] dynamic cart)
+ {
+ try
+ {
+ var result = await _CreateOrder(cart);
+ return StatusCode((int)result.StatusCode, result.Data);
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine("Failed to create order:", ex);
+ return StatusCode(500, new { error = "Failed to create order." });
+ }
+ }
+
+ private async Task _CreateOrder(dynamic cart)
+ {
+ CheckoutPaymentIntent intent = (CheckoutPaymentIntent)
+ Enum.Parse(typeof(CheckoutPaymentIntent), "CAPTURE", true);
+
+ OrdersCreateInput ordersCreateInput = new OrdersCreateInput
+ {
+ Body = new OrderRequest
+ {
+ Intent = intent,
+ PurchaseUnits = new List
+ {
+ new PurchaseUnitRequest
+ {
+ Amount = new AmountWithBreakdown { CurrencyCode = "USD", MValue = "100", },
+ },
+ },
+ },
+ };
+
+ ApiResponse result = await _ordersController.OrdersCreateAsync(ordersCreateInput);
+ return result;
+ }
+
+ [HttpPost("api/orders/{orderID}/capture")]
+ public async Task CaptureOrder(string orderID)
+ {
+ try
+ {
+ var result = await _CaptureOrder(orderID);
+ return StatusCode((int)result.StatusCode, result.Data);
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine("Failed to capture order:", ex);
+ return StatusCode(500, new { error = "Failed to capture order." });
+ }
+ }
+
+ private async Task _CaptureOrder(string orderID)
+ {
+ OrdersCaptureInput ordersCaptureInput = new OrdersCaptureInput { Id = orderID, };
+
+ ApiResponse result = await _ordersController.OrdersCaptureAsync(ordersCaptureInput);
+
+ return result;
+ }
+}
diff --git a/advanced-integration/v2/server/java/.gitignore b/advanced-integration/v2/server/java/.gitignore
new file mode 100644
index 00000000..9f970225
--- /dev/null
+++ b/advanced-integration/v2/server/java/.gitignore
@@ -0,0 +1 @@
+target/
\ No newline at end of file
diff --git a/advanced-integration/v2/server/java/.tool-versions b/advanced-integration/v2/server/java/.tool-versions
new file mode 100644
index 00000000..edcd84e6
--- /dev/null
+++ b/advanced-integration/v2/server/java/.tool-versions
@@ -0,0 +1 @@
+java zulu-21.36.19
diff --git a/advanced-integration/v2/server/java/README.md b/advanced-integration/v2/server/java/README.md
new file mode 100644
index 00000000..d88ad4a2
--- /dev/null
+++ b/advanced-integration/v2/server/java/README.md
@@ -0,0 +1,35 @@
+# Advanced Integration Java Sample
+
+PayPal Advanced Integration sample in Java
+
+## Running the sample
+
+1. Add your API credentials to the environment:
+
+ - **Windows (powershell)**
+
+ ```powershell
+ $env:PAYPAL_CLIENT_ID = ""
+ $env:PAYPAL_CLIENT_SECRET = ""
+ ```
+
+ - **Linux / MacOS**
+
+ ```bash
+ export PAYPAL_CLIENT_ID=""
+ export PAYPAL_CLIENT_SECRET=""
+ ```
+
+2. Build the server
+
+ ```bash
+ mvn clean install
+ ```
+
+3. Run the server
+
+ ```bash
+ mvn spring-boot:run
+ ```
+
+4. Go to [http://localhost:8080/](http://localhost:8080/)
diff --git a/advanced-integration/v2/server/java/pom.xml b/advanced-integration/v2/server/java/pom.xml
new file mode 100644
index 00000000..11002ca9
--- /dev/null
+++ b/advanced-integration/v2/server/java/pom.xml
@@ -0,0 +1,66 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.3.3
+
+
+ com.paypal.sample
+ advanced-integration
+ 0.0.1-SNAPSHOT
+ PayPal Advanced Integration
+ Sample Java demo application for PayPal JS SDK Advanced Integration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+ 3.3.3
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ 3.3.3
+
+
+
+ com.paypal.sdk
+
+
+ paypal-server-sdk
+
+
+ 0.5.1
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 3.3.3
+
+
+
+
+
diff --git a/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java b/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java
new file mode 100644
index 00000000..f34fef3a
--- /dev/null
+++ b/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java
@@ -0,0 +1,141 @@
+package com.paypal.sample;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.client.RestTemplate;
+
+import com.paypal.sdk.Environment;
+import com.paypal.sdk.PaypalServerSDKClient;
+import com.paypal.sdk.authentication.ClientCredentialsAuthModel;
+import com.paypal.sdk.controllers.OrdersController;
+import com.paypal.sdk.exceptions.ApiException;
+import com.paypal.sdk.http.response.ApiResponse;
+import com.paypal.sdk.models.AmountWithBreakdown;
+import com.paypal.sdk.models.CheckoutPaymentIntent;
+import com.paypal.sdk.models.Order;
+import com.paypal.sdk.models.OrderRequest;
+import com.paypal.sdk.models.OrdersCaptureInput;
+import com.paypal.sdk.models.OrdersCreateInput;
+import com.paypal.sdk.models.PurchaseUnitRequest;
+import java.util.Arrays;
+import org.slf4j.event.Level;
+
+import java.io.IOException;
+import java.util.Map;
+
+@SpringBootApplication
+public class SampleAppApplication {
+
+ @Value("${PAYPAL_CLIENT_ID}")
+ private String PAYPAL_CLIENT_ID;
+
+ @Value("${PAYPAL_CLIENT_SECRET}")
+ private String PAYPAL_CLIENT_SECRET;
+
+ public static void main(String[] args) {
+ SpringApplication.run(SampleAppApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+ @Bean
+ public PaypalServerSDKClient paypalClient() {
+ return new PaypalServerSDKClient.Builder()
+ .loggingConfig(builder -> builder
+ .level(Level.DEBUG)
+ .requestConfig(logConfigBuilder -> logConfigBuilder.body(true))
+ .responseConfig(logConfigBuilder -> logConfigBuilder.headers(true)))
+ .httpClientConfig(configBuilder -> configBuilder
+ .timeout(0))
+ .environment(Environment.SANDBOX)
+ .clientCredentialsAuth(new ClientCredentialsAuthModel.Builder(
+ PAYPAL_CLIENT_ID,
+ PAYPAL_CLIENT_SECRET)
+ .build())
+ .build();
+ }
+
+
+ @Controller
+ @RequestMapping("/")
+ public class CheckoutController {
+
+ private final ObjectMapper objectMapper;
+ private final PaypalServerSDKClient client;
+
+ public CheckoutController(ObjectMapper objectMapper, PaypalServerSDKClient client) {
+ this.objectMapper = objectMapper;
+ this.client = client;
+ }
+
+ @PostMapping("/api/orders")
+ public ResponseEntity createOrder(@RequestBody Map request) {
+ try {
+ String cart = objectMapper.writeValueAsString(request.get("cart"));
+ Order response = createOrder(cart);
+ return new ResponseEntity<>(response, HttpStatus.OK);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @PostMapping("/api/orders/{orderID}/capture")
+ public ResponseEntity captureOrder(@PathVariable String orderID) {
+ try {
+ Order response = captureOrders(orderID);
+ return new ResponseEntity(response, HttpStatus.OK);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ private Order createOrder(String cart) throws IOException, ApiException {
+
+ OrdersCreateInput ordersCreateInput = new OrdersCreateInput.Builder(
+ null,
+ new OrderRequest.Builder(
+ CheckoutPaymentIntent.CAPTURE,
+ Arrays.asList(
+ new PurchaseUnitRequest.Builder(
+ new AmountWithBreakdown.Builder(
+ "USD",
+ "100.00")
+ .build())
+ .build()))
+ .build())
+ .build();
+
+ OrdersController ordersController = client.getOrdersController();
+
+ ApiResponse apiResponse = ordersController.ordersCreate(ordersCreateInput);
+
+ return apiResponse.getResult();
+ }
+
+ private Order captureOrders(String orderID) throws IOException, ApiException {
+ OrdersCaptureInput ordersCaptureInput = new OrdersCaptureInput.Builder(
+ orderID,
+ null)
+ .build();
+ OrdersController ordersController = client.getOrdersController();
+ ApiResponse apiResponse = ordersController.ordersCapture(ordersCaptureInput);
+ return apiResponse.getResult();
+ }
+ }
+}
diff --git a/advanced-integration/v2/server/java/src/main/resources/application.properties b/advanced-integration/v2/server/java/src/main/resources/application.properties
new file mode 100644
index 00000000..103551b3
--- /dev/null
+++ b/advanced-integration/v2/server/java/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.application.name=v2-java
+PAYPAL_CLIENT_ID=${PAYPAL_CLIENT_ID}
+PAYPAL_CLIENT_SECRET=${PAYPAL_CLIENT_SECRET}
diff --git a/standard-integration/.env.example b/advanced-integration/v2/server/node/.env.example
similarity index 100%
rename from standard-integration/.env.example
rename to advanced-integration/v2/server/node/.env.example
diff --git a/advanced-integration/v2/server/node/README.md b/advanced-integration/v2/server/node/README.md
new file mode 100644
index 00000000..e2c1f93e
--- /dev/null
+++ b/advanced-integration/v2/server/node/README.md
@@ -0,0 +1,35 @@
+# Advanced Integration Node.js Sample
+
+PayPal Advanced Integration sample in Node.js
+
+## Running the sample
+
+1. Add your API credentials to the environment:
+
+ - **Windows (powershell)**
+
+ ```powershell
+ $env:PAYPAL_CLIENT_ID = ""
+ $env:PAYPAL_CLIENT_SECRET = ""
+ ```
+
+ - **Linux / MacOS**
+
+ ```bash
+ export PAYPAL_CLIENT_ID=""
+ export PAYPAL_CLIENT_SECRET=""
+ ```
+
+2. Install the packages
+
+ ```bash
+ npm install
+ ```
+
+3. Run the server
+
+ ```bash
+ npm run start
+ ```
+
+4. Go to [http://localhost:8080/](http://localhost:8080/)
diff --git a/advanced-integration/v2/server/node/package.json b/advanced-integration/v2/server/node/package.json
new file mode 100644
index 00000000..44735762
--- /dev/null
+++ b/advanced-integration/v2/server/node/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "paypal-advanced-integration-backend-node",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "dependencies": {
+ "@paypal/paypal-server-sdk": "^0.5.1",
+ "body-parser": "^1.20.3",
+ "dotenv": "^16.3.1",
+ "express": "^4.18.2"
+ },
+ "scripts": {
+ "server-dev": "nodemon server.js",
+ "start": "npm run server-dev",
+ "prod": "node server.js",
+ "format": "npx prettier --write **/*.{js,jsx,md}",
+ "format:check": "npx prettier --check **/*.{js,jsx,md}"
+ },
+ "devDependencies": {
+ "concurrently": "^8.2.1",
+ "nodemon": "^3.0.1"
+ }
+}
diff --git a/advanced-integration/v2/server/node/server.js b/advanced-integration/v2/server/node/server.js
new file mode 100644
index 00000000..08aadad1
--- /dev/null
+++ b/advanced-integration/v2/server/node/server.js
@@ -0,0 +1,127 @@
+import express from "express";
+import "dotenv/config";
+import {
+ ApiError,
+ CheckoutPaymentIntent,
+ Client,
+ Environment,
+ LogLevel,
+ OrdersController,
+} from "@paypal/paypal-server-sdk";
+import bodyParser from "body-parser";
+
+const app = express();
+app.use(bodyParser.json());
+
+const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8080 } = process.env;
+
+const client = new Client({
+ clientCredentialsAuthCredentials: {
+ oAuthClientId: PAYPAL_CLIENT_ID,
+ oAuthClientSecret: PAYPAL_CLIENT_SECRET,
+ },
+ timeout: 0,
+ environment: Environment.Sandbox,
+ logging: {
+ logLevel: LogLevel.Info,
+ logRequest: {
+ logBody: true,
+ },
+ logResponse: {
+ logHeaders: true,
+ },
+ },
+});
+
+const ordersController = new OrdersController(client);
+
+/**
+ * Create an order to start the transaction.
+ * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
+ */
+const createOrder = async (cart) => {
+ const collect = {
+ body: {
+ intent: CheckoutPaymentIntent.CAPTURE,
+ purchaseUnits: [
+ {
+ amount: {
+ currencyCode: "USD",
+ value: "100.00",
+ },
+ },
+ ],
+ },
+ prefer: "return=minimal",
+ };
+
+ try {
+ const { body, ...httpResponse } =
+ await ordersController.ordersCreate(collect);
+ // Get more response info...
+ // const { statusCode, headers } = httpResponse;
+ return {
+ jsonResponse: JSON.parse(body),
+ httpStatusCode: httpResponse.statusCode,
+ };
+ } catch (error) {
+ if (error instanceof ApiError) {
+ // const { statusCode, headers } = error;
+ throw new Error(error.message);
+ }
+ }
+};
+
+/**
+ * Capture payment for the created order to complete the transaction.
+ * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
+ */
+const captureOrder = async (orderID) => {
+ const collect = {
+ id: orderID,
+ prefer: "return=minimal",
+ };
+
+ try {
+ const { body, ...httpResponse } =
+ await ordersController.ordersCapture(collect);
+ // Get more response info...
+ // const { statusCode, headers } = httpResponse;
+ return {
+ jsonResponse: JSON.parse(body),
+ httpStatusCode: httpResponse.statusCode,
+ };
+ } catch (error) {
+ if (error instanceof ApiError) {
+ // const { statusCode, headers } = error;
+ throw new Error(error.message);
+ }
+ }
+};
+
+app.post("/api/orders", async (req, res) => {
+ try {
+ // use the cart information passed from the front-end to calculate the order amount detals
+ const { cart } = req.body;
+ const { jsonResponse, httpStatusCode } = await createOrder(cart);
+ res.status(httpStatusCode).json(jsonResponse);
+ } catch (error) {
+ console.error("Failed to create order:", error);
+ res.status(500).json({ error: "Failed to create order." });
+ }
+});
+
+app.post("/api/orders/:orderID/capture", async (req, res) => {
+ try {
+ const { orderID } = req.params;
+ const { jsonResponse, httpStatusCode } = await captureOrder(orderID);
+ res.status(httpStatusCode).json(jsonResponse);
+ } catch (error) {
+ console.error("Failed to create order:", error);
+ res.status(500).json({ error: "Failed to capture order." });
+ }
+});
+
+app.listen(PORT, () => {
+ console.log(`Node server listening at http://localhost:${PORT}/`);
+});
diff --git a/advanced-integration/v2/server/php/.gitignore b/advanced-integration/v2/server/php/.gitignore
new file mode 100644
index 00000000..a725465a
--- /dev/null
+++ b/advanced-integration/v2/server/php/.gitignore
@@ -0,0 +1 @@
+vendor/
\ No newline at end of file
diff --git a/advanced-integration/v2/server/php/README.md b/advanced-integration/v2/server/php/README.md
new file mode 100644
index 00000000..2bcecf8d
--- /dev/null
+++ b/advanced-integration/v2/server/php/README.md
@@ -0,0 +1,63 @@
+# Advanced Integration Sample Application - PHP
+
+This sample app demonstrates how to integrate with ACDC using PayPal's REST APIs.
+
+## Before You Code
+
+1. **Setup a PayPal Account**
+
+ To get started, you'll need a developer, personal, or business account.
+
+ [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer)
+
+ You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts.
+
+2. **Create an Application**
+
+ Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create).
+
+## How to Run Locally
+
+1. Add your API credentials to the environment:
+
+ - **Windows (powershell)**
+
+ ```powershell
+ $env:PAYPAL_CLIENT_ID = ""
+ $env:PAYPAL_CLIENT_SECRET = ""
+ ```
+
+ - **Linux / MacOS**
+
+ ```bash
+ export PAYPAL_CLIENT_ID=""
+ export PAYPAL_CLIENT_SECRET=""
+ ```
+
+2. Follow the below instructions to setup & run server.
+
+## Install the Composer
+
+We'll be using Composer (https://getcomposer.org/) for dependency management. To install Composer on a Mac, run the following command in the terminal:
+
+```bash
+brew install composer
+```
+
+Composer can be downloaded for Windows from this link: https://getcomposer.org/download/.
+
+## To install the dependencies
+
+```bash
+composer install
+```
+
+## To run the application in development, you can run this command
+
+```bash
+composer start
+```
+
+Afterward, open http://localhost:8080 in your browser.
+
+That's it!
diff --git a/advanced-integration/v2/server/php/composer.json b/advanced-integration/v2/server/php/composer.json
new file mode 100644
index 00000000..721ec31f
--- /dev/null
+++ b/advanced-integration/v2/server/php/composer.json
@@ -0,0 +1,16 @@
+{
+ "description": "PayPal JS SDK Advanced Integration - Checkout Flow",
+ "license": "MIT",
+ "require": {
+ "php": "^7.4 || ^8.0",
+ "ext-json": "*",
+ "paypal/paypal-server-sdk": "0.5.1"
+ },
+ "require-dev": {
+ },
+ "scripts": {
+ "start": "php -S localhost:8080 -t src"
+ },
+ "config": {
+ }
+}
diff --git a/advanced-integration/v2/server/php/composer.lock b/advanced-integration/v2/server/php/composer.lock
new file mode 100644
index 00000000..39a01f7b
--- /dev/null
+++ b/advanced-integration/v2/server/php/composer.lock
@@ -0,0 +1,387 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "d4a57a266f3f33beef57b02efc8cfaac",
+ "packages": [
+ {
+ "name": "apimatic/core",
+ "version": "0.3.11",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/apimatic/core-lib-php.git",
+ "reference": "2274f103f9f210664f546f504e4559d772a81fee"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/apimatic/core-lib-php/zipball/2274f103f9f210664f546f504e4559d772a81fee",
+ "reference": "2274f103f9f210664f546f504e4559d772a81fee",
+ "shasum": ""
+ },
+ "require": {
+ "apimatic/core-interfaces": "~0.1.5",
+ "apimatic/jsonmapper": "^3.1.1",
+ "ext-curl": "*",
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "php": "^7.2 || ^8.0",
+ "php-jsonpointer/php-jsonpointer": "^3.0.2",
+ "psr/log": "^1.1.4 || ^2.0.0 || ^3.0.0"
+ },
+ "require-dev": {
+ "phan/phan": "5.4.2",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Core\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Core logic and the utilities for the Apimatic's PHP SDK",
+ "homepage": "https://github.com/apimatic/core-lib-php",
+ "keywords": [
+ "apimatic",
+ "core",
+ "corelib",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/apimatic/core-lib-php/issues",
+ "source": "https://github.com/apimatic/core-lib-php/tree/0.3.11"
+ },
+ "time": "2024-07-08T11:50:08+00:00"
+ },
+ {
+ "name": "apimatic/core-interfaces",
+ "version": "0.1.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/apimatic/core-interfaces-php.git",
+ "reference": "b4f1bffc8be79584836f70af33c65e097eec155c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/apimatic/core-interfaces-php/zipball/b4f1bffc8be79584836f70af33c65e097eec155c",
+ "reference": "b4f1bffc8be79584836f70af33c65e097eec155c",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "CoreInterfaces\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Definition of the behavior of apimatic/core, apimatic/unirest-php and Apimatic's PHP SDK",
+ "homepage": "https://github.com/apimatic/core-interfaces-php",
+ "keywords": [
+ "apimatic",
+ "core",
+ "corelib",
+ "interface",
+ "php",
+ "unirest"
+ ],
+ "support": {
+ "issues": "https://github.com/apimatic/core-interfaces-php/issues",
+ "source": "https://github.com/apimatic/core-interfaces-php/tree/0.1.5"
+ },
+ "time": "2024-05-09T06:32:07+00:00"
+ },
+ {
+ "name": "apimatic/jsonmapper",
+ "version": "3.1.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/apimatic/jsonmapper.git",
+ "reference": "407b455d2adda2efa51a44b99400389fbee0394e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/apimatic/jsonmapper/zipball/407b455d2adda2efa51a44b99400389fbee0394e",
+ "reference": "407b455d2adda2efa51a44b99400389fbee0394e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "php": "^5.6 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
+ "squizlabs/php_codesniffer": "^3.0.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "apimatic\\jsonmapper\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "OSL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "Christian Weiske",
+ "email": "christian.weiske@netresearch.de",
+ "homepage": "http://www.netresearch.de/",
+ "role": "Developer"
+ },
+ {
+ "name": "Mehdi Jaffery",
+ "email": "mehdi.jaffery@apimatic.io",
+ "homepage": "http://apimatic.io/",
+ "role": "Developer"
+ }
+ ],
+ "description": "Map nested JSON structures onto PHP classes",
+ "support": {
+ "email": "mehdi.jaffery@apimatic.io",
+ "issues": "https://github.com/apimatic/jsonmapper/issues",
+ "source": "https://github.com/apimatic/jsonmapper/tree/3.1.4"
+ },
+ "time": "2024-06-11T11:48:30+00:00"
+ },
+ {
+ "name": "apimatic/unirest-php",
+ "version": "4.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/apimatic/unirest-php.git",
+ "reference": "e16754010c16be5473289470f129d87a0f41b55e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/apimatic/unirest-php/zipball/e16754010c16be5473289470f129d87a0f41b55e",
+ "reference": "e16754010c16be5473289470f129d87a0f41b55e",
+ "shasum": ""
+ },
+ "require": {
+ "apimatic/core-interfaces": "^0.1.0",
+ "ext-curl": "*",
+ "ext-json": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "phan/phan": "5.4.2",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Unirest\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mashape",
+ "email": "opensource@mashape.com",
+ "homepage": "https://www.mashape.com",
+ "role": "Developer"
+ },
+ {
+ "name": "APIMATIC",
+ "email": "opensource@apimatic.io",
+ "homepage": "https://www.apimatic.io",
+ "role": "Developer"
+ }
+ ],
+ "description": "Unirest PHP",
+ "homepage": "https://github.com/apimatic/unirest-php",
+ "keywords": [
+ "client",
+ "curl",
+ "http",
+ "https",
+ "rest"
+ ],
+ "support": {
+ "email": "opensource@apimatic.io",
+ "issues": "https://github.com/apimatic/unirest-php/issues",
+ "source": "https://github.com/apimatic/unirest-php/tree/4.0.5"
+ },
+ "time": "2023-04-25T14:19:45+00:00"
+ },
+ {
+ "name": "paypal/paypal-server-sdk",
+ "version": "0.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paypal/PayPal-PHP-Server-SDK.git",
+ "reference": "09148245f72f9dc2f6c8363b6206eac5effefa77"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paypal/PayPal-PHP-Server-SDK/zipball/09148245f72f9dc2f6c8363b6206eac5effefa77",
+ "reference": "09148245f72f9dc2f6c8363b6206eac5effefa77",
+ "shasum": ""
+ },
+ "require": {
+ "apimatic/core": "~0.3.11",
+ "apimatic/core-interfaces": "~0.1.5",
+ "apimatic/unirest-php": "^4.0.0",
+ "ext-json": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "phan/phan": "5.4.2",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "PaypalServerSDKLib\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PayPal's SDK for interacting with the REST APIs",
+ "homepage": "https://github.com/paypal/PayPal-PHP-Server-SDK",
+ "support": {
+ "issues": "https://github.com/paypal/PayPal-PHP-Server-SDK/issues",
+ "source": "https://github.com/paypal/PayPal-PHP-Server-SDK/tree/0.5.1"
+ },
+ "time": "2024-09-10T15:31:38+00:00"
+ },
+ {
+ "name": "php-jsonpointer/php-jsonpointer",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/raphaelstolt/php-jsonpointer.git",
+ "reference": "4428f86c6f23846e9faa5a420c4ef14e485b3afb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/raphaelstolt/php-jsonpointer/zipball/4428f86c6f23846e9faa5a420c4ef14e485b3afb",
+ "reference": "4428f86c6f23846e9faa5a420c4ef14e485b3afb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^1.11",
+ "phpunit/phpunit": "4.6.*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Rs\\Json": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Raphael Stolt",
+ "email": "raphael.stolt@gmail.com",
+ "homepage": "http://raphaelstolt.blogspot.com/"
+ }
+ ],
+ "description": "Implementation of JSON Pointer (http://tools.ietf.org/html/rfc6901)",
+ "homepage": "https://github.com/raphaelstolt/php-jsonpointer",
+ "keywords": [
+ "json",
+ "json pointer",
+ "json traversal"
+ ],
+ "support": {
+ "issues": "https://github.com/raphaelstolt/php-jsonpointer/issues",
+ "source": "https://github.com/raphaelstolt/php-jsonpointer/tree/master"
+ },
+ "time": "2016-08-29T08:51:01+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": "^7.4 || ^8.0",
+ "ext-json": "*"
+ },
+ "platform-dev": [],
+ "plugin-api-version": "2.6.0"
+}
diff --git a/advanced-integration/v2/server/php/src/.htaccess b/advanced-integration/v2/server/php/src/.htaccess
new file mode 100644
index 00000000..fe74ec5b
--- /dev/null
+++ b/advanced-integration/v2/server/php/src/.htaccess
@@ -0,0 +1,34 @@
+Options All -Indexes
+
+
+order allow,deny
+deny from all
+
+
+
+ RewriteEngine On
+
+ # Redirect to HTTPS
+ # RewriteEngine On
+ # RewriteCond %{HTTPS} off
+ # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
+
+ # Some hosts may require you to use the `RewriteBase` directive.
+ # Determine the RewriteBase automatically and set it as environment variable.
+ # If you are using Apache aliases to do mass virtual hosting or installed the
+ # project in a subdirectory, the base path will be prepended to allow proper
+ # resolution of the index.php file and to redirect to the correct URI. It will
+ # work in environments without path prefix as well, providing a safe, one-size
+ # fits all solution. But as you do not need it in this case, you can comment
+ # the following 2 lines to eliminate the overhead.
+ RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
+ RewriteRule ^(.*) - [E=BASE:%1]
+
+ # If the above doesn't work you might need to set the `RewriteBase` directive manually, it should be the
+ # absolute physical path to the directory that contains this htaccess file.
+ # RewriteBase /
+
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteRule ^ index.php [QSA,L]
+
diff --git a/advanced-integration/v2/server/php/src/index.php b/advanced-integration/v2/server/php/src/index.php
new file mode 100644
index 00000000..ee2b3d4c
--- /dev/null
+++ b/advanced-integration/v2/server/php/src/index.php
@@ -0,0 +1,117 @@
+clientCredentialsAuthCredentials(
+ ClientCredentialsAuthCredentialsBuilder::init(
+ $PAYPAL_CLIENT_ID,
+ $PAYPAL_CLIENT_SECRET
+ )
+ )
+ ->environment(Environment::SANDBOX)
+ ->build();
+
+/**
+ * Create an order to start the transaction.
+ * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
+ */
+function createOrder($cart)
+{
+ global $client;
+
+ $orderBody = [
+ 'body' => OrderRequestBuilder::init(
+ CheckoutPaymentIntent::CAPTURE,
+ [
+ PurchaseUnitRequestBuilder::init(
+ AmountWithBreakdownBuilder::init(
+ 'USD',
+ '100.00'
+ )->build()
+ )->build()
+ ]
+ )->build()
+ ];
+
+ $apiResponse = $client->getOrdersController()->ordersCreate($orderBody);
+
+ return handleResponse($apiResponse);
+}
+
+/**
+ * Capture payment for the created order to complete the transaction.
+ * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
+ */
+function captureOrder($orderID)
+{
+ global $client;
+
+ $captureBody = [
+ 'id' => $orderID
+ ];
+
+ $apiResponse = $client->getOrdersController()->ordersCapture($captureBody);
+
+ return handleResponse($apiResponse);
+}
+
+function handleResponse($response)
+{
+ return [
+ 'jsonResponse' => $response->getResult(),
+ 'httpStatusCode' => $response->getStatusCode()
+ ];
+}
+
+$endpoint = $_SERVER['REQUEST_URI'];
+if ($endpoint === '/') {
+ try {
+ $response = [
+ "message" => "Server is running"
+ ];
+ header('Content-Type: application/json');
+ echo json_encode($response);
+ } catch (Exception $e) {
+ echo json_encode(['error' => $e->getMessage()]);
+ http_response_code(500);
+ }
+}
+
+if ($endpoint === '/api/orders') {
+ $data = json_decode(file_get_contents('php://input'), true);
+ $cart = $data['cart'];
+ header('Content-Type: application/json');
+ try {
+ $orderResponse = createOrder($cart);
+ echo json_encode($orderResponse['jsonResponse']);
+ } catch (Exception $e) {
+ echo json_encode(['error' => $e->getMessage()]);
+ http_response_code(500);
+ }
+}
+
+
+if (str_ends_with($endpoint, '/capture')) {
+ $urlSegments = explode('/', $endpoint);
+ end($urlSegments); // Will set the pointer to the end of array
+ $orderID = prev($urlSegments);
+ header('Content-Type: application/json');
+ try {
+ $captureResponse = captureOrder($orderID);
+ echo json_encode($captureResponse['jsonResponse']);
+ } catch (Exception $e) {
+ echo json_encode(['error' => $e->getMessage()]);
+ http_response_code(500);
+ }
+}
diff --git a/advanced-integration/v2/server/python/.flaskenv b/advanced-integration/v2/server/python/.flaskenv
new file mode 100644
index 00000000..c6cbe150
--- /dev/null
+++ b/advanced-integration/v2/server/python/.flaskenv
@@ -0,0 +1 @@
+FLASK_RUN_PORT=8080
\ No newline at end of file
diff --git a/advanced-integration/v2/server/python/README.md b/advanced-integration/v2/server/python/README.md
new file mode 100644
index 00000000..de523758
--- /dev/null
+++ b/advanced-integration/v2/server/python/README.md
@@ -0,0 +1,41 @@
+# Standard Integration Python Flask Sample
+
+PayPal Standard Integration sample in Python using Flask
+
+## Running the sample
+
+1. **Setup a virtual environment**
+
+ ```sh
+ python3 -m venv .venv
+ ```
+
+1. **Install the dependencies**
+
+ ```sh
+ pip install -r requirements.txt
+ ```
+
+1. **Add your API credentials to the environment:**
+
+ - **Windows**
+
+ ```powershell
+ $env:PAYPAL_CLIENT_ID = ""
+ $env:PAYPAL_CLIENT_SECRET = ""
+ ```
+
+ - **Unix**
+
+ ```bash
+ export PAYPAL_CLIENT_ID=""
+ export PAYPAL_CLIENT_SECRET=""
+ ```
+
+1. **Run the server**
+
+ ```sh
+ flask --app server run
+ ```
+
+1. Go to [http://localhost:8080/](http://localhost:8080/)
diff --git a/advanced-integration/v2/server/python/requirements.txt b/advanced-integration/v2/server/python/requirements.txt
new file mode 100644
index 00000000..7a44eadf
--- /dev/null
+++ b/advanced-integration/v2/server/python/requirements.txt
@@ -0,0 +1,2 @@
+Flask==3.0.3
+paypal-server-sdk==0.5.2
\ No newline at end of file
diff --git a/advanced-integration/v2/server/python/server.py b/advanced-integration/v2/server/python/server.py
new file mode 100644
index 00000000..2cf004a3
--- /dev/null
+++ b/advanced-integration/v2/server/python/server.py
@@ -0,0 +1,86 @@
+import logging
+import os
+
+from flask import Flask, request
+from paypalserversdk.http.auth.o_auth_2 import ClientCredentialsAuthCredentials
+from paypalserversdk.logging.configuration.api_logging_configuration import LoggingConfiguration, \
+ RequestLoggingConfiguration, ResponseLoggingConfiguration
+from paypalserversdk.paypalserversdk_client import PaypalserversdkClient
+from paypalserversdk.controllers.orders_controller import OrdersController
+from paypalserversdk.models.amount_with_breakdown import AmountWithBreakdown
+from paypalserversdk.models.checkout_payment_intent import CheckoutPaymentIntent
+from paypalserversdk.models.order_request import OrderRequest
+from paypalserversdk.models.purchase_unit_request import PurchaseUnitRequest
+from paypalserversdk.api_helper import ApiHelper
+
+app = Flask(__name__)
+
+paypal_client: PaypalserversdkClient = PaypalserversdkClient(
+ client_credentials_auth_credentials=ClientCredentialsAuthCredentials(
+ o_auth_client_id=os.getenv('PAYPAL_CLIENT_ID'),
+ o_auth_client_secret=os.getenv('PAYPAL_CLIENT_SECRET')
+ ),
+ logging_configuration=LoggingConfiguration(
+ log_level=logging.INFO,
+ # Disable masking of sensitive headers for Sandbox testing.
+ # This should be set to True (the default if unset)in production.
+ mask_sensitive_headers=False,
+ request_logging_config=RequestLoggingConfiguration(
+ log_headers=True,
+ log_body=True
+ ),
+ response_logging_config=ResponseLoggingConfiguration(
+ log_headers=True,
+ log_body=True
+ )
+ )
+)
+
+'''
+Health check
+'''
+@app.route('/', methods=['GET'])
+def index():
+ return {"message": "Server is running"}
+
+orders_controller: OrdersController = paypal_client.orders
+
+'''
+Create an order to start the transaction.
+
+@see https://developer.paypal.com/docs/api/orders/v2/#orders_create
+'''
+@app.route('/api/orders', methods=['POST'])
+def create_order():
+ request_body = request.get_json()
+ # use the cart information passed from the front-end to calculate the order amount detals
+ cart = request_body['cart']
+ order = orders_controller.orders_create({
+ "body": OrderRequest(
+ intent=CheckoutPaymentIntent.CAPTURE,
+ purchase_units=[
+ PurchaseUnitRequest(
+ AmountWithBreakdown(
+ currency_code='USD',
+ value='100.00'
+ )
+ )
+ ]
+ ),
+ "prefer": 'return=representation'
+ }
+ )
+ return ApiHelper.json_serialize(order.body)
+
+'''
+ Capture payment for the created order to complete the transaction.
+
+ @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
+'''
+@app.route('/api/orders//capture', methods=['POST'])
+def capture_order(order_id):
+ order = orders_controller.orders_capture({
+ 'id': order_id,
+ 'prefer': 'return=representation'
+ })
+ return ApiHelper.json_serialize(order.body)
\ No newline at end of file
diff --git a/advanced-integration/v2/server/ruby/.ruby-version b/advanced-integration/v2/server/ruby/.ruby-version
new file mode 100644
index 00000000..fa7adc7a
--- /dev/null
+++ b/advanced-integration/v2/server/ruby/.ruby-version
@@ -0,0 +1 @@
+3.3.5
diff --git a/advanced-integration/v2/server/ruby/Gemfile b/advanced-integration/v2/server/ruby/Gemfile
new file mode 100644
index 00000000..a5b31725
--- /dev/null
+++ b/advanced-integration/v2/server/ruby/Gemfile
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+source "https://rubygems.org"
+
+gem "paypal-server-sdk", "~> 0.5.2"
+gem "puma", "~> 6.4"
+gem "rackup", "~> 2.1"
+gem "sinatra", "~> 4.0"
+gem "sinatra-contrib", "~> 4.0"
\ No newline at end of file
diff --git a/advanced-integration/v2/server/ruby/README.md b/advanced-integration/v2/server/ruby/README.md
new file mode 100644
index 00000000..6ad18fe2
--- /dev/null
+++ b/advanced-integration/v2/server/ruby/README.md
@@ -0,0 +1,37 @@
+# Standard Integration Ruby Sinatra Sample
+
+PayPal Standard Integration sample in Ruby using Sinatra
+
+## Running the sample
+
+1. **Ensure you have a supported Ruby version installed**: [Ruby Maintenance Branches](https://www.ruby-lang.org/en/downloads/branches/)
+
+1. **Install the dependencies**
+
+ ```bash
+ bundle install
+ ```
+
+1. **Add your API credentials to the environment:**
+
+ - **Windows**
+
+ ```powershell
+ $env:PAYPAL_CLIENT_ID = ""
+ $env:PAYPAL_CLIENT_SECRET = ""
+ ```
+
+ - **Unix**
+
+ ```bash
+ export PAYPAL_CLIENT_ID=""
+ export PAYPAL_CLIENT_SECRET=""
+ ```
+
+1. **Run the server**
+
+ ```bash
+ bundle exec ruby server.rb
+ ```
+
+1. Go to [http://localhost:8080/](http://localhost:8080/)
diff --git a/advanced-integration/v2/server/ruby/server.rb b/advanced-integration/v2/server/ruby/server.rb
new file mode 100644
index 00000000..6f0987c8
--- /dev/null
+++ b/advanced-integration/v2/server/ruby/server.rb
@@ -0,0 +1,67 @@
+require 'paypal_server_sdk'
+require 'sinatra'
+require 'sinatra/json'
+
+include PaypalServerSdk
+
+set :port, 8080
+
+paypal_client = PaypalServerSdk::Client.new(
+ client_credentials_auth_credentials: ClientCredentialsAuthCredentials.new(
+ o_auth_client_id: ENV['PAYPAL_CLIENT_ID'],
+ o_auth_client_secret: ENV['PAYPAL_CLIENT_SECRET']
+ ),
+ environment: Environment::SANDBOX,
+ logging_configuration: LoggingConfiguration.new(
+ mask_sensitive_headers: false,
+ log_level: Logger::INFO,
+ request_logging_config: RequestLoggingConfiguration.new(
+ log_headers: true,
+ log_body: true,
+ ),
+ response_logging_config: ResponseLoggingConfiguration.new(
+ log_headers: true,
+ log_body: true
+ )
+ )
+)
+
+# Health Check
+get '/' do
+ json :message => "Server is running"
+end
+
+# Create an order to start the transaction.
+#
+# @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
+post "/api/orders" do
+ # use the cart information passed from the front-end to calculate the order amount detals
+ cart = JSON.parse request.body.read
+ order_response = paypal_client.orders.orders_create({
+ 'body' => OrderRequest.new(
+ intent: CheckoutPaymentIntent::CAPTURE,
+ purchase_units: [
+ PurchaseUnitRequest.new(
+ amount: AmountWithBreakdown.new(
+ currency_code: 'USD',
+ value: '100.00'
+ )
+ )
+ ]
+ ),
+ 'prefer' => 'return=representation'
+ })
+ json order_response.data
+end
+
+# Capture payment for the created order to complete the transaction.
+#
+# @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
+post '/api/orders/:order_id/capture' do |order_id|
+ capture_response = paypal_client.orders.orders_capture({
+ 'id' => order_id,
+ 'prefer' => 'return=representation'
+ })
+ json capture_response.data
+rescue ErrorException => e
+end
\ No newline at end of file
diff --git a/save-payment-method/.env.example b/save-payment-method/.env.example
new file mode 100644
index 00000000..2251fbbb
--- /dev/null
+++ b/save-payment-method/.env.example
@@ -0,0 +1,5 @@
+# Create an application to obtain credentials at
+# https://developer.paypal.com/dashboard/applications/sandbox
+
+PAYPAL_CLIENT_ID=YOUR_CLIENT_ID_GOES_HERE
+PAYPAL_CLIENT_SECRET=YOUR_SECRET_GOES_HERE
diff --git a/standard-integration/.gitignore b/save-payment-method/.gitignore
similarity index 100%
rename from standard-integration/.gitignore
rename to save-payment-method/.gitignore
diff --git a/standard-integration/README.md b/save-payment-method/README.md
similarity index 50%
rename from standard-integration/README.md
rename to save-payment-method/README.md
index c0bf83f3..f1f4a0e9 100644
--- a/standard-integration/README.md
+++ b/save-payment-method/README.md
@@ -1,12 +1,14 @@
-# Standard Integration Example
+# Save Payment Method Example
-This folder contains example code for a Standard PayPal integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API.
+This folder contains example code for a PayPal Save Payment Method integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API.
+
+[View the Documentation](https://developer.paypal.com/docs/checkout/save-payment-methods/during-purchase/js-sdk/paypal/)
## Instructions
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 `client/index.html` with your app's client-id
+3. Replace `test` in [client/app.js](client/app.js) 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/save-payment-method/client/app.js
similarity index 94%
rename from standard-integration/client/app.js
rename to save-payment-method/client/app.js
index cab942a0..eebd2017 100644
--- a/standard-integration/client/app.js
+++ b/save-payment-method/client/app.js
@@ -69,8 +69,11 @@ window.paypal
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`,
+ `Transaction ${transaction.status}: ${transaction.id}
See console for all available details.
+ See the return buyer experience
+ `,
);
+
console.log(
"Capture result",
orderData,
diff --git a/standard-integration/package.json b/save-payment-method/package.json
similarity index 67%
rename from standard-integration/package.json
rename to save-payment-method/package.json
index 5413d87e..d1596b09 100644
--- a/standard-integration/package.json
+++ b/save-payment-method/package.json
@@ -1,6 +1,6 @@
{
- "name": "paypal-standard-integration",
- "description": "Sample Node.js web app to integrate PayPal Standard Checkout for online payments",
+ "name": "paypal-save-payment-method",
+ "description": "Sample Node.js web app to integrate PayPal Save Payment Method for online payments",
"version": "1.0.0",
"main": "server/server.js",
"type": "module",
@@ -9,11 +9,12 @@
"start": "nodemon server/server.js",
"format": "npx prettier --write **/*.{js,md}",
"format:check": "npx prettier --check **/*.{js,md}",
- "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser"
+ "lint": "npx eslint server/*.js client/*.js --no-config-lookup"
},
"license": "Apache-2.0",
"dependencies": {
"dotenv": "^16.3.1",
+ "ejs": "^3.1.9",
"express": "^4.18.2",
"node-fetch": "^3.3.2"
},
diff --git a/standard-integration/server/server.js b/save-payment-method/server/server.js
similarity index 76%
rename from standard-integration/server/server.js
rename to save-payment-method/server/server.js
index 0d8d3cb8..7d2596f2 100644
--- a/standard-integration/server/server.js
+++ b/save-payment-method/server/server.js
@@ -1,12 +1,14 @@
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.set("views", "./server/views");
+
// host static files
app.use(express.static("client"));
@@ -17,7 +19,15 @@ app.use(express.json());
* Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs.
* @see https://developer.paypal.com/api/rest/authentication/
*/
-const generateAccessToken = async () => {
+const authenticate = async (bodyParams) => {
+ const params = {
+ grant_type: "client_credentials",
+ response_type: "id_token",
+ ...bodyParams,
+ };
+
+ // pass the url encoded value as the body of the post call
+ const urlEncodedParams = new URLSearchParams(params).toString();
try {
if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) {
throw new Error("MISSING_API_CREDENTIALS");
@@ -25,21 +35,25 @@ const generateAccessToken = async () => {
const auth = Buffer.from(
PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET,
).toString("base64");
+
const response = await fetch(`${base}/v1/oauth2/token`, {
method: "POST",
- body: "grant_type=client_credentials",
+ body: urlEncodedParams,
headers: {
Authorization: `Basic ${auth}`,
},
});
-
- const data = await response.json();
- return data.access_token;
+ return handleResponse(response);
} catch (error) {
console.error("Failed to generate Access Token:", error);
}
};
+const generateAccessToken = async () => {
+ const { jsonResponse } = await authenticate();
+ return jsonResponse.access_token;
+};
+
/**
* Create an order to start the transaction.
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
@@ -59,10 +73,26 @@ const createOrder = async (cart) => {
{
amount: {
currency_code: "USD",
- value: "100.00",
+ value: "110.00",
},
},
],
+ payment_source: {
+ paypal: {
+ attributes: {
+ vault: {
+ store_in_vault: "ON_SUCCESS",
+ usage_type: "MERCHANT",
+ customer_type: "CONSUMER",
+ },
+ },
+ experience_context: {
+ return_url: "http://example.com",
+ cancel_url: "http://example.com",
+ shipping_preference: "NO_SHIPPING",
+ },
+ },
+ },
};
const response = await fetch(url, {
@@ -135,6 +165,7 @@ app.post("/api/orders/:orderID/capture", async (req, res) => {
try {
const { orderID } = req.params;
const { jsonResponse, httpStatusCode } = await captureOrder(orderID);
+ console.log("capture response", jsonResponse);
res.status(httpStatusCode).json(jsonResponse);
} catch (error) {
console.error("Failed to create order:", error);
@@ -142,9 +173,19 @@ app.post("/api/orders/:orderID/capture", async (req, res) => {
}
});
-// serve index.html
-app.get("/", (req, res) => {
- res.sendFile(path.resolve("./client/checkout.html"));
+// render checkout page with client id & user id token
+app.get("/", async (req, res) => {
+ try {
+ const { jsonResponse } = await authenticate({
+ target_customer_id: req.query.customerID,
+ });
+ res.render("checkout", {
+ clientId: PAYPAL_CLIENT_ID,
+ userIdToken: jsonResponse.id_token,
+ });
+ } catch (err) {
+ res.status(500).send(err.message);
+ }
});
app.listen(PORT, () => {
diff --git a/save-payment-method/server/views/checkout.ejs b/save-payment-method/server/views/checkout.ejs
new file mode 100644
index 00000000..69cd3e78
--- /dev/null
+++ b/save-payment-method/server/views/checkout.ejs
@@ -0,0 +1,17 @@
+
+
+
+
+
+ PayPal JS SDK Save Payment Method Integration
+
+
+
+
+
+
+
+
diff --git a/standard-integration/client/checkout.html b/standard-integration/client/checkout.html
deleted file mode 100644
index 7b959c2f..00000000
--- a/standard-integration/client/checkout.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
- PayPal JS SDK Standard Integration
-
-
-
-
-
-
-
-
-
diff --git a/standard-integration/client/html/.env.example b/standard-integration/client/html/.env.example
new file mode 100644
index 00000000..dbfed9bd
--- /dev/null
+++ b/standard-integration/client/html/.env.example
@@ -0,0 +1,4 @@
+# Create an application to obtain credentials at
+# https://developer.paypal.com/dashboard/applications/sandbox
+
+PAYPAL_CLIENT_ID=YOUR_CLIENT_ID_GOES_HERE
diff --git a/standard-integration/client/html/.gitignore b/standard-integration/client/html/.gitignore
new file mode 100644
index 00000000..ed648a05
--- /dev/null
+++ b/standard-integration/client/html/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+*.local
\ No newline at end of file
diff --git a/standard-integration/client/html/README.md b/standard-integration/client/html/README.md
new file mode 100644
index 00000000..fba52a4b
--- /dev/null
+++ b/standard-integration/client/html/README.md
@@ -0,0 +1,74 @@
+# Standard Integration with PayPal : HTML/JS
+
+## Getting Started
+
+This guide will walk you through setting up and running the HTML/JS Standard Integration locally.
+
+### Before You Code
+
+1. **Setup a PayPal Account**
+
+ To get started, you'll need a developer, personal, or business account.
+
+ [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer)
+
+ You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts.
+
+2. **Create an Application**
+
+ Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create).
+
+### Installation
+
+```bash
+npm install
+```
+
+### Configuration
+
+1. Environmental Variables (.env)
+
+ - Rename the .env.example file to .env
+ - Update the following keys with their actual values -
+
+ ```bash
+ PAYPAL_CLIENT_ID=
+ ```
+
+2. Connecting the client and server (vite.config.js)
+
+ - Open vite.config.js in the root directory.
+ - Locate the proxy configuration object.
+ - Update the proxy key to match the server's address and port. For example:
+
+ ```js
+ export default defineConfig({
+
+ server: {
+ proxy: {
+ "/api": {
+ target: "http://localhost:8080", // Replace with your server URL
+ changeOrigin: true,
+ },
+ },
+ },
+ });
+ ```
+
+3. Starting the development server
+
+ - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory.
+
+ - **Start the client**:
+
+ ```bash
+ npm run start
+ ```
+
+ This will start the development server, and you should be able to access the Standard Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output).
+
+### Additional Notes
+
+- **Server Setup**: Make sure you have the server up and running before starting the client.
+- **Environment Variables**: Carefully configure the environment variables in the .env file to match your setup.
+- **Proxy Configuration**: The proxy setting in vite.config.js is crucial for routing API requests from the client to the server during development.
diff --git a/standard-integration/client/html/package.json b/standard-integration/client/html/package.json
new file mode 100644
index 00000000..4685f847
--- /dev/null
+++ b/standard-integration/client/html/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "paypal-standard-integration-frontend-html",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "vite build",
+ "preview": "vite preview",
+ "start": "vite",
+ "format": "npx prettier --write **/*.{js,md}",
+ "format:check": "npx prettier --check **/*.{js,md}"
+ },
+ "devDependencies": {
+ "dotenv": "^16.4.5",
+ "vite": "^5.4.2"
+ }
+}
diff --git a/standard-integration/client/html/src/app.js b/standard-integration/client/html/src/app.js
new file mode 100644
index 00000000..685b2c46
--- /dev/null
+++ b/standard-integration/client/html/src/app.js
@@ -0,0 +1,106 @@
+window.paypal
+ .Buttons({
+ style: {
+ shape: "rect",
+ layout: "vertical",
+ color: "gold",
+ label: "paypal",
+ },
+ message: {
+ amount: 100,
+ },
+
+ async createOrder() {
+ 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;
+ }
+ 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}`);
+ }
+ },
+
+ async onApprove(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/html/src/index.html b/standard-integration/client/html/src/index.html
new file mode 100644
index 00000000..f993cfc1
--- /dev/null
+++ b/standard-integration/client/html/src/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+ PayPal JS SDK Standard Integration
+
+
+
+
+
+
+
+
+
+
diff --git a/standard-integration/client/html/vite.config.js b/standard-integration/client/html/vite.config.js
new file mode 100644
index 00000000..0a14da0e
--- /dev/null
+++ b/standard-integration/client/html/vite.config.js
@@ -0,0 +1,19 @@
+import { defineConfig } from 'vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [],
+ envDir: "../",
+ envPrefix: "PAYPAL",
+ root: "src",
+ server: {
+ port: 3000,
+ proxy: {
+ "/api": {
+ target: "http://localhost:8080",
+ changeOrigin: true,
+ secure: false,
+ },
+ },
+ },
+})
\ No newline at end of file
diff --git a/standard-integration/client/react/.env.example b/standard-integration/client/react/.env.example
new file mode 100644
index 00000000..abea0386
--- /dev/null
+++ b/standard-integration/client/react/.env.example
@@ -0,0 +1 @@
+PAYPAL_CLIENT_ID=PAYPAL_CLIENT_ID
\ No newline at end of file
diff --git a/standard-integration/client/react/.gitignore b/standard-integration/client/react/.gitignore
new file mode 100644
index 00000000..ed648a05
--- /dev/null
+++ b/standard-integration/client/react/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+*.local
\ No newline at end of file
diff --git a/standard-integration/client/react/README.md b/standard-integration/client/react/README.md
new file mode 100644
index 00000000..208ccd52
--- /dev/null
+++ b/standard-integration/client/react/README.md
@@ -0,0 +1,74 @@
+# Standard Integration with PayPal : React
+
+## Getting Started
+
+This guide will walk you through setting up and running the React Standard Integration locally.
+
+### Before You Code
+
+1. **Setup a PayPal Account**
+
+ To get started, you'll need a developer, personal, or business account.
+
+ [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer)
+
+ You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts.
+
+2. **Create an Application**
+
+ Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create).
+
+### Installation
+
+```bash
+npm install
+```
+
+### Configuration
+
+1. Environmental Variables (.env)
+
+ - Rename the .env.example file to .env
+ - Update the following keys with their actual values -
+
+ ```bash
+ PAYPAL_CLIENT_ID=
+ ```
+
+2. Connecting the client and server (vite.config.js)
+
+ - Open vite.config.js in the root directory.
+ - Locate the proxy configuration object.
+ - Update the proxy key to match the server's address and port. For example:
+
+ ```js
+ export default defineConfig({
+
+ server: {
+ proxy: {
+ "/api": {
+ target: "http://localhost:8080", // Replace with your server URL
+ changeOrigin: true,
+ },
+ },
+ },
+ });
+ ```
+
+3. Starting the development server
+
+ - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory.
+
+ - **Start the client**:
+
+ ```bash
+ npm run start
+ ```
+
+ This will start the development server, and you should be able to access the Standard Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output).
+
+### Additional Notes
+
+- **Server Setup**: Make sure you have the server up and running before starting the client.
+- **Environment Variables**: Carefully configure the environment variables in the .env file to match your setup.
+- **Proxy Configuration**: The proxy setting in vite.config.js is crucial for routing API requests from the client to the server during development.
diff --git a/standard-integration/client/react/package.json b/standard-integration/client/react/package.json
new file mode 100644
index 00000000..2ce526a8
--- /dev/null
+++ b/standard-integration/client/react/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "paypal-standard-integration-frontend-react",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "dependencies": {
+ "@paypal/react-paypal-js": "^8.6.0",
+ "dotenv": "^16.3.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "scripts": {
+ "client-dev": "vite",
+ "client-build": "vite build",
+ "client-preview": "vite preview",
+ "start": "npm run client-dev",
+ "format": "npx prettier --write **/*.{js,jsx,md}",
+ "format:check": "npx prettier --check **/*.{js,jsx,md}"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react": "^4.3.1",
+ "vite": "^5.4.2"
+ }
+}
diff --git a/standard-integration/client/react/src/App.jsx b/standard-integration/client/react/src/App.jsx
new file mode 100644
index 00000000..ec740440
--- /dev/null
+++ b/standard-integration/client/react/src/App.jsx
@@ -0,0 +1,123 @@
+import React, { useState } from "react";
+import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js";
+
+// Renders errors or successfull transactions on the screen.
+function Message({ content }) {
+ return