This breakdown focuses on key lines from the paypal-api.js
code sample.
Imports
This line of code imports the fetch function from the Node-Fetch library.
1import fetch from "node-fetch"
Grab variables and sandbox URL
This section of code grabs the environment variables and sets the base sandbox URL.
3// set some important variables4const { CLIENT_ID, APP_SECRET } = process.env;5const base = "https://api-m.sandbox.paypal.com";
- Line 4 uses the DotEnv library to import and declare the client ID and app secret from your .env file.
- Line 5 declares the base URL for PayPal’s sandbox API.
Create order
Create an order to start a payment between a payer and a seller by making a POST
request to /v2/checkout/orders
.
Important: If you process payments that require Strong Customer Authentication, you need to provide additional context with payment indicators.
7// call the create order method8export async function createOrder() {9 const purchaseAmount = "100.00";10 // TODO: pull prices from a database11 const accessToken = await generateAccessToken();12 const url = `${base}/v2/checkout/orders`;13 const response = await fetch(url, {14 method: "post",15 headers: {16 "Content-Type": "application/json",17 Authorization: `Bearer ${accessToken}`,18 },19 body: JSON.stringify({20 intent: "CAPTURE",21 purchase_units: [22 {23 amount: {24 currency_code: "USD",25 value: purchaseAmount,26 },27 },28 ],29 }),30 });31 return handleResponse(response);32}
- Line 9 declares a static price to use for testing. You can change this to a dynamic value before going live.
- Line 11 establishes a listener to capture the
accessToken
from thegenerateAccessToken()
function later in the API call. - Lines 12-30 create an order by sending a POST request to the Orders v2 API, using the
accessToken
.
Note: Visit the Create Order endpoint of the PayPal Orders v2 API to see sample responses and other details.
Payment processors return processor response codes when they receive a transaction request. For advanced card payments, the code displays in the authorization object under the response_code
field.
This sample shows the processor response codes that are returned in the response of authorization and capture calls:
1"processor_response": {2"avs_code": "Y",3"cvv_code": "S",4"payment_advice_code": "",5"response_code": "0000"6}
If an external payment processor declines a transaction, PayPal returns a HTTP 201 Created
status code and a status of DECLINED
in the capture status.
See the Orders API response_code
object to get the processor response code for the non-PayPal payment processor errors.
Generate access token
You need an access token to authenticate all REST API requests. The following code sample creates an access token for you by making a POST
call to the /v1/oauth2/
token endpoint.
49// generate access token50export async function generateAccessToken() {51const auth = Buffer.from(CLIENT_ID + ":" + APP_SECRET).toString("base64");52const response = await fetch(`${base}/v1/oauth2/token`, {53 method: "post",54 body: "grant_type=client_credentials",55 headers: {56 Authorization: `Basic ${auth}`,57 },58});59const jsonData = await handleResponse(response);60return jsonData.access_token;61}
- Line 51 combines the
CLIENT_ID
andAPP_SECRET
as a key:value pair. - Lines 52-58 define a
response
that makes aPOST
call to the/v1/oauth2/token
API endpoint to generate an access token. - Lines 59-60 establish a listener to capture the response
jsonData
from the request and return theaccess_token
.
- Sample access token request
- Sample access token response
1curl -v -X POST "https://api-m.sandbox.paypal.com/v1/oauth2/token"2 -u "CLIENT_ID:CLIENT_SECRET"3 -H "Content-Type: application/x-www-form-urlencoded"4 -d "grant_type=client_credentials"
Note: Read more about authenticating with PayPal.
Generate client token
A client token uniquely identifies your payer. You need a client token to use card fields. The following code sample creates a client token for you by making a POST
call to the /v1/identity/generate-token
endpoint.
63// generate client token64export async function generateClientToken() {65 const accessToken = await generateAccessToken();66 const response = await fetch(`${base}/v1/identity/generate-token`, {67 method: "post",68 headers: {69 Authorization: `Bearer ${accessToken}`,70 "Accept-Language": "en_US",71 "Content-Type": "application/json",72 },73 });74 console.log('response', response.status)75 const jsonData = await handleResponse(response);76 return jsonData.client_token;77}
- Line 65 sets up a listener to capture the
accessToken
from thegenerateAccessToken()
function. - Lines 66-73 make a
POST
call to the/v1/identity/generate-token
API endpoint to generate a client token. - Lines 75-76 establish a listener to capture the response
jsonData
from the request and return theclient_token
.
- Sample client token request
- Sample client token response
1curl -X POST https://api-m.sandbox.paypal.com/v1/identity/generate-token \2 -H 'Content-Type: application/json' \3 -H 'Authorization: Bearer ACCESS-TOKEN' \4 -H 'PayPal-Partner-Attribution-Id: BN-CODE \5 -H 'Accept-Language: en_US'
Tip: Because each payer session is unique, set up your server to generate a new client token each time the card fields render on your page.
Handle responses
The handleResponse
function sets up a listener for API responses.
79async function handleResponse(response) {80 if (response.status === 200 || response.status === 201) {81 return response.json();82 }8384 const errorMessage = await response.text();85 throw new Error(errorMessage);86 }
- Line 80 declares which HTTP status codes return a response. Other status codes return an error message.
Capture payment
Capture an order to successfully move money from the payer's payment method to the seller by making a POST
call to /v2/checkout/orders/${orderId}/capture
.
34// capture payment for an order35 export async function capturePayment(orderId) {36 const accessToken = await generateAccessToken();37 const url = `${base}/v2/checkout/orders/${orderId}/capture`;38 const response = await fetch(url, {39 method: "post",40 headers: {41 "Content-Type": "application/json",42 Authorization: `Bearer ${accessToken}`,43 },44 });4546 return handleResponse(response);47 }
- Line 36 establishes a listener to capture the
accessToken
from thegenerateAccessToken()
function later in the API call. - Line 37 declares the URL of the Capture API endpoint using the Order ID generated from the Create Order endpoint.
- Lines 38-43 define a
response
that makes aPOST
call to the/v2/checkout/orders/${orderId}/capture
API endpoint to capture the order, using theaccessToken
.
Sample capture response
This code sample shows a response to a POST
call to /v2/checkout/orders/{id}/capture
. This response is the orderData
that is grabbed by lines 71-72 in Render hosted card fields and create order section.
1{2 "id": "5O190127TN364715T",3 "status": "COMPLETED",4 "payment_source": {5 "paypal": {6 "name": {7 "given_name": "Firstname",8 "surname": "Lastname",9 },10 "email_address": "payer@example.com",11 "account_id": "QYR5Z8XDVJNXQ",12 },13 },14 "purchase_units": [15 {16 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",17 "shipping": {18 "address": {19 "address_line_1": "123 Main St.",20 "admin_area_2": "Anytown",21 "admin_area_1": "CA",22 "postal_code": "12345",23 "country_code": "US",24 },25 },26 "payments": {27 "captures": [28 {29 "id": "3C679366HH908993F",30 "status": "COMPLETED",31 "amount": {32 "currency_code": "USD",33 "value": "100.00",34 },35 "seller_protection": {36 "status": "ELIGIBLE",37 "dispute_categories": [38 "ITEM_NOT_RECEIVED",39 "UNAUTHORIZED_TRANSACTION",40 ],41 },42 "final_capture": true,43 "disbursement_mode": "INSTANT",44 "seller_receivable_breakdown": {45 "gross_amount": {46 "currency_code": "USD",47 "value": "100.00",48 },49 "paypal_fee": {50 "currency_code": "USD",51 "value": "3.00",52 },53 "net_amount": {54 "currency_code": "USD",55 "value": "97.00",56 },57 },58 "create_time": "2018-04-01T21:20:49Z",59 "update_time": "2018-04-01T21:20:49Z",60 "links": [61 {62 "href": "https://api-m.paypal.com/v2/payments/captures/3C679366HH908993F",63 "rel": "self",64 "method": "GET",65 },66 {67 "href": "https://api-m.paypal.com/v2/payments/captures/3C679366HH908993F/refund",68 "rel": "refund",69 "method": "POST",70 },71 ],72 },73 ],74 },75 },76 ],77 "payer": {78 "name": {79 "given_name": "Firstname",80 "surname": "Lastname",81 },82 "email_address": "payer@example.com",83 "payer_id": "QYR5Z8XDVJNXQ",84 },85 "links": [86 {87 "href": "https://api-m.paypal.com/v2/checkout/orders/5O190127TN364715T",88 "rel": "self",89 "method": "GET",90 },91 ],92 }
- Line 2 shows the id for this
orderData
object. - Lines 4-13 pass details about the payment source.
- Lines 14-76 pass the
purchase_units
in this transaction. Each purchase unit establishes a contract between a customer and merchant. Each purchase unit represents either a full or partial order that the customer intends to purchase from the merchant. - Line 16 passes the
reference_id
that identifies the 1 purchase unit in this payment response. - Lines 17-24 pass details about the shipping address.
- Line 26 declares the payments object that passes the payment details for this capture request.
- Line 27 declares the captures object that passes details about the captured payments for this request.
- Lines 28-57 pass the payment capture details, such as the capture identifier
id
,amount
,disbursement_mode
, andnet_amount
. - Lines 60-71 pass the HATEOAS details of the capture response. See our REST API Response Reference for more details about HATEOAS.
- Lines 77-84 pass details about the payer.
- Lines 85-91 pass the HATEOAS details for the orders response.
See the Capture payment for order API endpoint for more details about the capture response.