Standard payments with single-page applications for direct merchants
DocsCurrentLast updated: March 16th 2023, @ 11:23:55 am
Use this guide if your integration uses a single-page application to accept payments, built on a library or framework such as React, Vue, or Angular.
Know before you code
Complete the steps in Get started to get the following sandbox REST API credentials from the Developer Dashboard:
- Client ID: Authenticates your account with PayPal and identifies an app in your sandbox.
- Client secret: Authorizes an app in your sandbox. Keep this secret safe and don’t share it.
- Access token.
Use Postman to explore and test PayPal APIs.
1. Add JavaScript SDK
The JavaScript SDK shows your payer's available payment methods on your checkout page.
Set up the PayPal checkout for your application by using the JavaScript SDK and handling the payer's interactions with the PayPal checkout button.
Place the following script
tag in your index.html
page based on how you plan to render payment buttons, so the paypal
object is available when you need it in the checkout flow. You can render the payment buttons either immediately, or after user action, navigation, or other page change:
- Immediate
- On change
1<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>
Modify the code
Note: This sample code is optimized for JavaScript performance. To learn more about how to optimize the JavaScript SDK, see JavaScript SDK performance optimization.
- Copy the sample JavaScript SDK code and paste it into your checkout page.
- In the SDK code, replace
YOUR_CLIENT_ID
with your client ID. - Pass parameters to replace default values, such as
USD
forcurrency
. To learn more about the default values, see the JavaScript SDK script configuration.
2. Add payment buttons driver
Add payment buttons to your single-page application's library or framework:
- React
- Angular
- Angular 2
- Vue
1const PayPalButton = paypal.Buttons.driver("react", { React, ReactDOM });
3. Add payment buttons to app
Choose your JavaScript library or framework:
React
Component implementation and functional implementation.
Component implementation
1import React from "react";2import ReactDOM from "react-dom"3const PayPalButton = paypal.Buttons.driver("react", { React, ReactDOM });4class YourComponent extends React.Component {5 createOrder(data) {6 // Order is created on the server and the order id is returned7 return fetch("/my-server/create-paypal-order", {8 method: "POST",9 headers: {10 "Content-Type": "application/json",11 },12 // use the "body" param to optionally pass additional order information13 // like product skus and quantities14 body: JSON.stringify({15 cart: [16 {17 sku: "YOUR_PRODUCT_STOCK_KEEPING_UNIT",18 quantity: "YOUR_PRODUCT_QUANTITY",19 },20 ],21 }),22 })23 .then((response) => response.json())24 .then((order) => order.id);25 }26 onApprove(data) {27 // Order is captured on the server28 return fetch("/my-server/capture-paypal-order", {29 method: "POST",30 headers: {31 "Content-Type": "application/json",32 },33 body: JSON.stringify({34 orderID: data.orderID35 })36 })37 .then((response) => response.json());38 }39 render() {40 return (41 <PayPalButton42 createOrder={(data, actions) => this.createOrder(data)}43 onApprove={(data, actions) => this.onApprove(data)}44 />45 );46 }47}
Functional implementation
1import React from "react";2import ReactDOM from "react-dom"3const PayPalButton = paypal.Buttons.driver("react", { React, ReactDOM });4function YourComponent() {5 const createOrder = (data) => {6 // Order is created on the server and the order id is returned7 return fetch("/my-server/create-paypal-order", {8 method: "POST",9 headers: {10 "Content-Type": "application/json",11 },12 // use the "body" param to optionally pass additional order information13 // like product skus and quantities14 body: JSON.stringify({15 cart: [16 {17 sku: "YOUR_PRODUCT_STOCK_KEEPING_UNIT",18 quantity: "YOUR_PRODUCT_QUANTITY",19 },20 ],21 }),22 })23 .then((response) => response.json())24 .then((order) => order.id);25 };26 const onApprove = (data) => {27 // Order is captured on the server and the response is returned to the browser28 return fetch("/my-server/capture-paypal-order", {29 method: "POST",30 headers: {31 "Content-Type": "application/json",32 },33 body: JSON.stringify({34 orderID: data.orderID35 })36 })37 .then((response) => response.json());38 };39 return (40 <PayPalButton41 createOrder={(data) => createOrder(data, actions)}42 onApprove={(data) => onApprove(data, actions)}43 />44 );45}
Angular
1paypal.Buttons.driver("angular", window.angular);2angular3 .module("app", ["paypal-buttons"])4 .controller("appController", function ($scope) {5 $scope.opts = {6 createOrder: function (data) {7 // Order is created on the server and the order id is returned8 return fetch("/my-server/create-paypal-order", {9 method: "POST",10 headers: {11 "Content-Type": "application/json",12 },13 // use the "body" param to optionally pass additional order information14 // like product skus and quantities15 body: JSON.stringify({16 cart: [17 {18 sku: "YOUR_PRODUCT_STOCK_KEEPING_UNIT",19 quantity: "YOUR_PRODUCT_QUANTITY",20 },21 ],22 }),23 })24 .then((response) => response.json())25 .then((order) => order.id);26 },27 onApprove: function (data) {28 // Order is captured on the server29 return fetch("/my-server/capture-paypal-order", {30 method: "POST",31 headers: {32 "Content-Type": "application/json",33 },34 body: JSON.stringify({35 orderID: data.orderID36 })37 })38 .then((response) => response.json());39 },40 };41 });
1<body ng-app="app" ng-controller="appController">2 <paypal-buttons props="opts"></paypal-buttons>3</body>
Angular 2
1(function () {2 const PayPalButton = paypal.Buttons.driver("angular2", ng.core);3 const appComponent = ng.core4 .Component({5 selector: "my-app",6 template:7 <div id="app">8 <paypal-buttons [props]="{9 createOrder: createOrder,10 onApprove: onApprove11 }"></paypal-buttons>12 </div>13 ,14 })15 .Class({16 constructor: function () {17 this.createOrder = (function(data) {18 // Order is created on the server and the order id is returned19 return fetch("/my-server/create-paypal-order", {20 method: "POST",21 headers: {22 "Content-Type": "application/json",23 },24 // use the "body" param to optionally pass additional order information25 // like product skus and quantities26 body: JSON.stringify({27 cart: [28 {29 sku: "YOUR_PRODUCT_STOCK_KEEPING_UNIT",30 quantity: "YOUR_PRODUCT_QUANTITY",31 },32 ],33 }),34 })35 .then((response) => response.json())36 .then((order) => order.id);37 }).bind(this);38 this.onApprove = (function(data, actions) {39 // Order is captured on the server40 return fetch("/my-server/capture-paypal-order", {41 method: "POST",42 headers: {43 "Content-Type": "application/json",44 },45 body: JSON.stringify({46 orderID: data.orderID47 })48 })49 .then((response) => response.json());50 }).bind(this);51 });52 }});53 const appModule = ng.core54 .NgModule({55 imports: [ng.platformBrowser.BrowserModule, PayPalButton],56 declarations: [appComponent],57 bootstrap: [appComponent],58 })59 .Class({60 constructor: function () {},61 });62 document.addEventListener("DOMContentLoaded", function () {63 ng.platformBrowserDynamic64 .platformBrowserDynamic()65 .bootstrapModule(appModule);66 });67})();
1(function () {2 const PayPalButton = paypal.Buttons.driver("angular2", ng.core);3 const appComponent = ng.core4 .Component({5 selector: "my-app",6 template:7 <div id="app">8 <paypal-buttons [props]="{9 createOrder: createOrder,10 onApprove: onApprove11 }"></paypal-buttons>12 </div>13 ,14 })15 .Class({16 constructor: function () {17 this.createOrder = (function(data) {18 // Order is created on the server and the order id is returned19 return fetch("/my-server/create-paypal-order", {20 method: "POST",21 headers: {22 "Content-Type": "application/json",23 },24 // use the "body" param to optionally pass additional order information25 // like product skus and quantities26 body: JSON.stringify({27 cart: [28 {29 sku: "YOUR_PRODUCT_STOCK_KEEPING_UNIT",30 quantity: "YOUR_PRODUCT_QUANTITY",31 },32 ],33 }),34 })35 .then((response) => response.json())36 .then((order) => order.id);37 }).bind(this);38 this.onApprove = (function(data) {39 // Order is captured on the server40 return fetch("/my-server/capture-paypal-order", {41 method: "POST",42 headers: {43 "Content-Type": "application/json",44 },45 body: JSON.stringify({46 orderID: data.orderID47 })48 })49 .then((response) => response.json());50 }).bind(this);51 });52 }});53 const appModule = ng.core54 .NgModule({55 imports: [ng.platformBrowser.BrowserModule, PayPalButton],56 declarations: [appComponent],57 bootstrap: [appComponent],58 })59 .Class({60 constructor: function () {},61 });62 document.addEventListener("DOMContentLoaded", function () {63 ng.platformBrowserDynamic64 .platformBrowserDynamic()65 .bootstrapModule(appModule);66 });67})();
Angular 2 using TypeScript
1@ng.core.Component({2 selector: 'my-app',3 template:4 <div id="app">5 <paypal-buttons [props]="{6 createOrder: createOrder,7 onApprove: onApprove8 }"></paypal-buttons>9 </div>10 ,11})12class AppComponent {13 createOrder(data) {14 // Order is created on the server and the order id is returned15 return fetch("/my-server/create-paypal-order", {16 method: "POST",17 headers: {18 "Content-Type": "application/json",19 },20 // use the "body" param to optionally pass additional order information21 // like product skus and quantities22 body: JSON.stringify({23 cart: [24 {25 sku: "YOUR_PRODUCT_STOCK_KEEPING_UNIT",26 quantity: "YOUR_PRODUCT_QUANTITY",27 },28 ],29 }),30 })31 .then((response) => response.json())32 .then((order) => order.id);33 }34 onApprove(data, actions) {35 // Order is captured on the server36 return fetch("/my-server/capture-paypal-order", {37 method: "POST",38 headers: {39 "Content-Type": "application/json",40 },41 body: JSON.stringify({42 orderID: data.orderID43 })44 })45 .then((response) => response.json());46 }47}48@ng.core.NgModule({49 imports: [50 ng.platformBrowser.BrowserModule,51 paypal.Buttons.driver('angular2', ng.core)52 ],53 declarations: [54 AppComponent55 ],56 bootstrap: [57 AppComponent58 ]59})60class AppModule {}61ng.platformBrowserDynamic62 .platformBrowserDynamic()63 .bootstrapModule(AppModule);
Vue
1<div id="container">2 <app></app>3</div>4<script>5 const PayPalButton = paypal.Buttons.driver('vue', window.Vue)67 Vue.component("app", {8 // The style prop for the PayPal button should be passed in as `style-object` or `styleObject` to avoid conflict with Vue's `style` reserved prop.9 template: `10 <paypal-buttons :on-approve="onApprove" :create-order="createOrder" :on-shipping-change="onShippingChange" :on-error="onError" :style-object="style" />11 `,12 components: {13 "paypal-buttons": PayPalButton,14 },1516 computed: {17 createOrder: function () {18 return (data) => {19 // Order is created on the server and the order id is returned20 return fetch("/my-server/create-paypal-order", {21 method: "POST",22 headers: {23 "Content-Type": "application/json",24 },25 // use the "body" param to optionally pass additional order information26 // like product skus and quantities27 body: JSON.stringify({28 cart: [29 {30 sku: "YOUR_PRODUCT_STOCK_KEEPING_UNIT",31 quantity: "YOUR_PRODUCT_QUANTITY",32 },33 ],34 }),35 })36 .then((response) => response.json())37 .then((order) => order.id);38 }39 },40 onApprove: function () {41 return (data) => {42 // Order is captured on the server43 return fetch("/my-server/capture-paypal-order", {44 method: "POST",45 headers: {46 "Content-Type": "application/json",47 },48 body: JSON.stringify({49 orderID: data.orderID50 })51 })52 .then((response) => response.json());53 }54 },55 onShippingChange: function () {56 return (data, actions) => {57 if (data.shipping_address.country_code !== 'US') {58 return actions.reject();59 }60 return actions.resolve();61 }62 },63 onError: function () {64 return (err) => {65 console.error(err);66 window.location.href = "/your-error-page-here";67 }68 },69 style: function () {70 return {71 shape: 'pill',72 color: 'gold',73 layout: 'horizontal',74 label: 'paypal',75 tagline: false,76 }77 },78 },79 });8081 const vm = new Vue({82 el: "#container",83 });84</script>
Next steps
Test in the PayPal sandbox, then go live in PayPal's live environment.