Integrate card payments

PayPal Checkout plus customized card fields

SDKCurrentAdvancedLast updated: May 9th 2023, @ 6:56:47 am


Know before you code

  • This integration is available to select partners only.
  • Complete Onboard Sellers before you begin this integration. During seller onboarding, pass PPCP as the value for product name.
  • You must have an access token.
  • You must toggle on the Advanced Debit and Credit Card Payments setting in your REST app settings to use this integration.
  • This integration is a PCI Compliant - SAQ A solution for accepting credit card payments directly on your website.
  • Advanced credit and debit cards requires that your business account be evaluated and approved by PayPal. You'll complete this process when you onboard in Step 1.
  • (UK merchants) Credit is a regulated activity in the UK. Before integrating a PayPal Credit button, you must be authorized to act as a credit broker and have a credit agreement with PayPal. For more information, contact business customer support through paypal.com or by calling 0800 358 7929.

  • This client-side and server-side integration uses the following:
  • Use Postman to explore and test PayPal APIs.

1. Generate client token

A client token is required to uniquely identify your buyer.

The following request generates a client token that you'll use for data-client-token when you integrate the JavaScript SDK script in Step 3.

Copy the following code and modify it.

Sample client token request

1curl -X POST https://api-m.sandbox.paypal.com/v1/identity/generate-token -H 'Content-Type: application/json' -H 'Authorization: Bearer <ACCESS-TOKEN>' -H 'PayPal-Partner-Attribution-Id: <BN-Code>' -H 'Accept-Language: en_US'

Modify the code

  1. Copy the sample request code.
  2. Change <ACCESS_TOKEN> to your access token.

Sample client token response

1{
2 "client_token": "eyJicmFpbnRyZWUiOnsiYXV0aG9yaXphdGlvbkZpbmdlcnByaW50IjoiYjA0MWE2M2JlMTM4M2NlZGUxZTI3OWFlNDlhMWIyNzZlY2FjOTYzOWU2NjlhMGIzODQyYTdkMTY3NzcwYmY0OHxtZXJjaGFudF9pZD1yd3dua3FnMnhnNTZobTJuJnB1YmxpY19rZXk9czlic3BuaGtxMmYzaDk0NCZjcmVhdGVkX2F0PTIwMTgtMTEtMTRUMTE6MTg6MDAuMTU3WiIsInZlcnNpb24iOiIzLXBheXBhbCJ9LCJwYXlwYWwiOnsiYWNjZXNzVG9rZW4iOiJBMjFBQUhNVExyMmctVDlhSTJacUZHUmlFZ0ZFZGRHTGwxTzRlX0lvdk9ESVg2Q3pSdW5BVy02TzI2MjdiWUJ2cDNjQ0FNWi1lTFBNc2NDWnN0bDUyNHJyUGhUQklJNlBBIn19",
3 "expires_in": 3600
4}

A successful response contains a client token.

Tip: Because each buyer session is unique, set up your server to generate a new client token each time the card fields render on your page.

2. Add JavaScript SDK and card form

To accept payments on your website, add the PayPal JavaScript SDK code with card form elements to your checkout page.

Sample JavaScript SDK code

This fully-styled sample code adds payment buttons and card fields to your website that capture the payment immediately.

1<html>
2<head>
3<meta charset="utf-8"/>
4 <meta name="viewport" content="width=device-width, initial-scale=1">
5 <link rel="stylesheet" type="text/css" href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css"/>
6</head>
7<body>
8<script src="https://www.paypal.com/sdk/js?components=buttons,hosted-fields&client-id=<CLIENT_ID>&merchant-id=<MERCHANT_ID>&currency=USD&intent=capture" data-partner-attribution-id="<BN_CODE>" data-client-token="<CLIENT_TOKEN>"></script>
9 <table border="0" align="center" valign="top" bgcolor="#FFFFFF" style="width: 39%">
10 <tr>
11 <td colspan="2">
12 <div id="paypal-button-container"></div>
13 </td>
14 </tr>
15 <tr><td colspan="2">&nbsp;</td></tr>
16 </table>
17 <div align="center"> or </div>
18 <div class="card_container">
19 <form id="card-form">
20 <label for="card-number">Card Number</label><div id="card-number" class="card_field"></div>
21 <div>
22 <label for="expiration-date">Expiration Date</label>
23 <div id="expiration-date" class="card_field"></div>
24 </div>
25 <div>
26 <label for="cvv">CVV</label><div id="cvv" class="card_field"></div>
27 </div>
28 <label for="card-holder-name">Name on Card</label>
29 <input type="text" id="card-holder-name" name="card-holder-name" autocomplete="off" placeholder="card holder name"/>
30 <div>
31 <label for="card-billing-address-street">Billing Address</label>
32 <input type="text" id="card-billing-address-street" name="card-billing-address-street" autocomplete="off" placeholder="street address"/>
33 </div>
34 <div>
35 <label for="card-billing-address-unit">&nbsp;</label>
36 <input type="text" id="card-billing-address-unit" name="card-billing-address-unit" autocomplete="off" placeholder="unit"/>
37 </div>
38 <div>
39 <input type="text" id="card-billing-address-city" name="card-billing-address-city" autocomplete="off" placeholder="city"/>
40 </div>
41 <div>
42 <input type="text" id="card-billing-address-state" name="card-billing-address-state" autocomplete="off" placeholder="state"/>
43 </div>
44 <div>
45 <input type="text" id="card-billing-address-zip" name="card-billing-address-zip" autocomplete="off" placeholder="zip / postal code"/>
46 </div>
47 <div>
48 <input type="text" id="card-billing-address-country" name="card-billing-address-country" autocomplete="off" placeholder="country code" />
49 </div>
50 <br/><br/>
51 <button value="submit" id="submit" class="btn">Pay</button>
52 </form>
53 </div>
54 <script>
55 let orderId;
56 paypal.Buttons({
57 style: {
58 layout: 'horizontal'
59 },
60 createOrder: function(data, actions) {
61 return actions.order.create({
62 purchase_units: [{
63 amount: {
64 value: "1.00"
65 }
66 }]
67 });
68 },
69 onApprove: function(data, actions) {
70 return actions.order.capture().then(function(details) {
71 window.location.href = '/success.html';
72 });
73 }
74 }).render("#paypal-button-container");
75 if (paypal.HostedFields.isEligible()) {
76 paypal.HostedFields.render({
77 createOrder: function () {
78 return fetch('/your-server/paypal/order', {
79 method: 'post'
80 }).then(function(res) {
81 return res.json();
82 }).then(function(orderData) {
83 orderId = orderData.id;
84 return orderId;
85 });
86 },
87 styles: {
88 '.valid': {
89 'color': 'green'
90 },
91 '.invalid': {
92 'color': 'red'
93 }
94 },
95 fields: {
96 number: {
97 selector: "#card-number",
98 placeholder: "4111 1111 1111 1111"
99 },
100 cvv: {
101 selector: "#cvv",
102 placeholder: "123"
103 },
104 expirationDate: {
105 selector: "#expiration-date",
106 placeholder: "MM/YY"
107 }
108 }
109 }).then(function (cardFields) {
110 document.querySelector("#card-form").addEventListener('submit', (event) => {
111 event.preventDefault();
112 cardFields.submit({
113 cardholderName: document.getElementById('card-holder-name').value,
114 billingAddress: {
115 streetAddress: document.getElementById('card-billing-address-street').value,
116 extendedAddress: document.getElementById('card-billing-address-unit').value,
117 region: document.getElementById('card-billing-address-state').value,
118 locality: document.getElementById('card-billing-address-city').value,
119 postalCode: document.getElementById('card-billing-address-zip').value,
120 countryCodeAlpha2: document.getElementById('card-billing-address-country').value
121 }
122 }).then(function () {
123 fetch('/your-server/api/order/' + orderId + '/capture/', {
124 method: 'post'
125 }).then(function(res) {
126 return res.json();
127 }).then(function (orderData) {
128 var errorDetail = Array.isArray(orderData.details) && orderData.details[0];
129 if (errorDetail) {
130 var msg = 'Sorry, your transaction could not be processed.';
131 if (errorDetail.description) msg += '
132
133' + errorDetail.description;
134 if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
135 return alert(msg); // Show a failure message
136 }
137 alert('Transaction completed!');
138 })
139 }).catch(function (err) {
140 alert('Payment could not be captured! ' + JSON.stringify(err))
141 });
142 });
143 });
144 } else {
145 document.querySelector("#card-form").style = 'display: none';
146 }
147 </script>
148 </body>
149 </html>

Modify the code

  1. Copy the sample JavaScript SDK code and paste it into the code for your checkout page.
  2. The components=buttons,hosted-fields parameter displays PayPal buttons and card fields component.
  3. If you onboard sellers before payment:
    • Pass the partner's client ID in the client-id query parameter. The client ID generates the access token required to make PayPal API calls in sandbox or production.
      • with your PayPal account.
      • Under the DASHBOARD menu, select My Apps & Credentials.
    • Pass the merchant ID of the seller you're facilitating a payment for in the merchant-id query parameter. The merchant ID is the seller's PayPal account ID. To get your seller's merchant ID, you can use one of the following:
      • read the merchantIdInPayPal query parameter attached to the return URL when the seller finishes PayPal onboarding and is redirected back to your site.
      • query it directly by the tracking_id you specified in the Partner Referrals call by calling GET /v1/customer/partners/partner_id/merchant-integrations?tracking_id=tracking_id.
  4. If you build onboarding into your software:
    • Pass your client ID in the client-id query parameter. The client ID generates the access token required to make PayPal API calls in sandbox or production.
      • with your account.
      • Under the DASHBOARD menu, select My Apps & Credentials.
  5. Change BN-Code to your PayPal Partner Attribution ID.
  6. Set intent to capture to immediately capture funds.
  7. Modify the createOrder function within the paypal.HostedFields.render() function to call your server and retrieve an Order ID (or EC token) using the Orders REST API or your existing PayPal API integration.

Tip: The JavaScript SDK has configuration that you can override, including currency, intent, and other attributes.

If you process payments that require Strong Customer Authentication (SCA), you need to provide additional context about the transaction with payment indicators.

Payment processor codes

Payment processors return the following 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 represents 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.

3. Capture order

If you're not redirecting your buyer to a review page after a successful approval, make sure you have logic in your server-side code that can immediately capture the order when a buyer pays with a credit or debit card. Server-side code keeps you from exposing your access token on the client.

1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/<ORDER-ID>/capture -H "Content-Type: application/json" -H 'Authorization: Bearer <ACCESS-TOKEN>' -H 'PayPal-Partner-Attribution-Id: <BN-Code>' -H 'Accept-Language: en_US'
  1. Copy the sample request code.
  2. Change <ORDER-ID> to the Order ID (or EC token) that you used to set up the transaction in your createOrder function.
  3. Change <ACCESS_TOKEN> to your access token.
  4. Change BN-Code to your PayPal Partner Attribution ID.

See also

You can move on to styling your card fields and testing a purchase.

4. Style card fields

Style the card fields to align with your brand using the CSS properties supported by this integration.

Next steps

  • Set up server-side code to ensure cart completion when a customer uses an alternative payment method. Alternative payment methods include bank accounts, wallets, and local payment methods.
  • (Europe) Implement 3D Secure.
  • Go live with this integration.

See also

Requirements

API response handling

Reference