PayPal Checkout Accept PayPal Checkout payments with Angular, React, or Vue 830 words. By Jeff Delaney Created Jun 23, 2019 Last Updated Jun 23, 2019 Code Slack #angular #react #vue #payments #paypal In February 2019, the PayPal Checkout API received a much needed facelift that brought massive improvements to the developer experience. The new v2 API has detailed documentation on par with Stripe and offers one of the smoothest paths to start accepting payments and/or subscriptions in a progressive web app. The following lesson will show you how to start accepting payments entirely from your frontend JavaScript code with PayPal Checkout with your choice of Angular, React, and Vue. If you're looking to implement a fullstack payment solution, check out the [Stripe Payments Master Course](/courses/stripe). Ironically, you can pay for it with PayPal if you prefer 🤷. Both PayPal and Stripe share similar APIs, so concepts from the course overlap both APIs. Live Demo The button below is the actual live implementation used for Fireship (Angular Elements). Try it 👇 Initial Setup PayPal Credentials Create an new REST API app from the PayPal developer applications screen. PayPal provides two sets of API keys. The sandbox keys are used for testing, while the live keys are used to process real payments. Each set of keys contains a client ID and secret. For basic checkout integrations, you only need the Client ID and can capture charges entirely from the frontend. Optionally, you can use the secret key to capture charges on a backend server (never expose the secret key in the frontend code or a public git repo). PayPal API credentials Testing PayPal provides testing accounts that you can use to make mock transactions. Change the password to something you’ll remember and use it to test out your first payment. Mock PayPal accounts for payment testing Angular Generate the App Create a new Angular project with the CLI. command line ng new myApp Add the PayPal Script Tag In Angular, we can simply include the script in the head of the HTML. Replace the value of the Client ID. file_type_html index.html <head> <!-- ... other stuff --> <script src="https://www.paypal.com/sdk/js?client-id=YOUR-CLIENT-ID"> </script> </head> Payment Component In the HTML, we need a template reference of a DOM element that PayPal will replace with the button. file_type_html some.component.html <div *ngIf="!paidFor"> <h1>Buy this Couch - ${{ product.price }} OBO</h1> </div> <div *ngIf=paidFor> <h1>Yay, you bought a sweet couch!</h1> </div> <div #paypal></div> file_type_ng_component_ts some.component.ts import { Component, OnInit, ViewChild, ElementRef } from '@angular/core'; declare var paypal; @Component({ selector: 'app-payme', templateUrl: './payme.component.html', styleUrls: ['./payme.component.css'] }) export class PaymeComponent implements OnInit { @ViewChild('paypal', { static: true }) paypalElement: ElementRef; product = { price: 777.77, description: 'used couch, decent condition', img: 'assets/couch.jpg' }; paidFor = false; ngOnInit() { paypal .Buttons({ createOrder: (data, actions) => { return actions.order.create({ purchase_units: [ { description: this.product.description, amount: { currency_code: 'USD', value: this.product.price } } ] }); }, onApprove: async (data, actions) => { const order = await actions.order.capture(); this.paidFor = true; console.log(order); }, onError: err => { console.log(err); } }) .render(this.paypalElement.nativeElement); } } React The react implementation takes advantage of Hooks to manage state and initialize the PayPal script tag. Generate the App Create a new React project with create-react-app. command line npx create-react-app my-app Payment Component file_type_js_official App.js import './App.css'; import React, { useState, useRef, useEffect } from 'react'; function Product({ product }) { const [paidFor, setPaidFor] = useState(false); const [error, setError] = useState(null); const paypalRef = useRef(); useEffect(() => { window.paypal .Buttons({ createOrder: (data, actions) => { return actions.order.create({ purchase_units: [ { description: product.description, amount: { currency_code: 'USD', value: product.price, }, }, ], }); }, onApprove: async (data, actions) => { const order = await actions.order.capture(); setPaidFor(true); console.log(order); }, onError: err => { setError(err); console.error(err); }, }) .render(paypalRef.current); }, [product.description, product.price]); if (paidFor) { return ( <div> <h1>Congrats, you just bought {product.name}!</h1> <img alt={product.description} src={gif} /> </div> ); } return ( <div> {error && <div>Uh oh, an error occurred! {error.message}</div>} <h1> {product.description} for ${product.price} </h1> <div ref={paypalRef} /> </div> ); } function App() { const product = { price: 777.77, name: 'comfy chair', description: 'fancy chair, like new', image: chair, }; return ( <div className="App"> <Product product={product} /> </div> ); } export default App; Vue Generate the App Create a new Vue app with the Vue CLI command line vue create my-app Payment Component Payments.vue <template> <div> <div v-if="!paidFor"> <h1>Buy this Lamp - ${{ product.price }} OBO</h1> <p>{{ product.description }}</p> </div> <div v-if="paidFor"> <h1>Noice, you bought a beautiful lamp!</h1> </div> <div ref="paypal"></div> </div> </template> <script> // import image from "../assets/lamp.png" export default { name: "HelloWorld", data: function() { return { loaded: false, paidFor: false, product: { price: 777.77, description: "leg lamp from that one movie", img: "./assets/lamp.jpg" } }; }, mounted: function() { const script = document.createElement("script"); script.src = "https://www.paypal.com/sdk/js?client-id=YOUR-CLIENT-ID"; script.addEventListener("load", this.setLoaded); document.body.appendChild(script); }, methods: { setLoaded: function() { this.loaded = true; window.paypal .Buttons({ createOrder: (data, actions) => { return actions.order.create({ purchase_units: [ { description: this.product.description, amount: { currency_code: "USD", value: this.product.price } } ] }); }, onApprove: async (data, actions) => { const order = await actions.order.capture(); this.paidFor = true; console.log(order); }, onError: err => { console.log(err); } }) .render(this.$refs.paypal); } } }; </script>