Integrate card payments

PayPal Checkout plus customized card fields

SDKCurrentAdvancedLast updated: April 6th 2022, @ 4:06:12 pm

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 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

curl -X POST \
-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

  "client_token": "eyJicmFpbnRyZWUiOnsiYXV0aG9yaXphdGlvbkZpbmdlcnByaW50IjoiYjA0MWE2M2JlMTM4M2NlZGUxZTI3OWFlNDlhMWIyNzZlY2FjOTYzOWU2NjlhMGIzODQyYTdkMTY3NzcwYmY0OHxtZXJjaGFudF9pZD1yd3dua3FnMnhnNTZobTJuJnB1YmxpY19rZXk9czlic3BuaGtxMmYzaDk0NCZjcmVhdGVkX2F0PTIwMTgtMTEtMTRUMTE6MTg6MDAuMTU3WiIsInZlcnNpb24iOiIzLXBheXBhbCJ9LCJwYXlwYWwiOnsiYWNjZXNzVG9rZW4iOiJBMjFBQUhNVExyMmctVDlhSTJacUZHUmlFZ0ZFZGRHTGwxTzRlX0lvdk9ESVg2Q3pSdW5BVy02TzI2MjdiWUJ2cDNjQ0FNWi1lTFBNc2NDWnN0bDUyNHJyUGhUQklJNlBBIn19",
  "expires_in": 3600

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.


  <meta charset="utf-8"/>

  <!-- Optimal rendering on mobile devices. -->
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <!-- Sample CSS styles for demo purposes. You can override these styles to match your web page's branding. -->
  <link rel="stylesheet" type="text/css" href=""/>


<!-- JavaScript SDK -->
 <script src=",hosted-fields&client-id=<YOUR-CLIENT-ID>" data-client-token="<Client-ID>">&amp;merchant-id="<Merchant-ID>"&amp;currency=USD&amp;intent=capture data-partner-attribution-id="<BN-Code>" data-client-token="<Client-Token>"</script>

   <!-- Buttons container -->
   <table border="0" align="center" valign="top" bgcolor="#FFFFFF" style="width: 39%">
       <td colspan="2">
         <div id="paypal-button-container"></div>
     <tr><td colspan="2">&nbsp;</td></tr>

   <div align="center"> or </div>

   <!-- Advanced credit and debit card payments form -->
   <div class="card_container">
     <form id="card-form">

       <label for="card-number">Card Number</label><div id="card-number" class="card_field"></div>
         <label for="expiration-date">Expiration Date</label>
         <div id="expiration-date" class="card_field"></div>
         <label for="cvv">CVV</label><div id="cvv" class="card_field"></div>
       <label for="card-holder-name">Name on Card</label>
       <input type="text" id="card-holder-name" name="card-holder-name" autocomplete="off" placeholder="card holder name"/>
         <label for="card-billing-address-street">Billing Address</label>
         <input type="text" id="card-billing-address-street" name="card-billing-address-street" autocomplete="off" placeholder="street address"/>
         <label for="card-billing-address-unit">&nbsp;</label>
         <input type="text" id="card-billing-address-unit" name="card-billing-address-unit" autocomplete="off" placeholder="unit"/>
         <input type="text" id="card-billing-address-city" name="card-billing-address-city" autocomplete="off" placeholder="city"/>
         <input type="text" id="card-billing-address-state" name="card-billing-address-state" autocomplete="off" placeholder="state"/>
         <input type="text" id="card-billing-address-zip" name="card-billing-address-zip" autocomplete="off" placeholder="zip / postal code"/>
         <input type="text" id="card-billing-address-country" name="card-billing-address-country" autocomplete="off" placeholder="country code" />
       <button value="submit" id="submit" class="btn">Pay</button>

   <!-- Implementation -->
     let orderId;

     // Displays PayPal buttons
       style: {
         layout: 'horizontal'
        createOrder: function(data, actions) {
           return actions.order.create({
             purchase_units: [{
               amount: {
                 value: "1.00"
         onApprove: function(data, actions) {
           return actions.order.capture().then(function(details) {
             window.location.href = '/success.html';

     // If this returns false or the card fields aren't visible, see Step #1.
     if (paypal.HostedFields.isEligible()) {

       // Renders card fields
         // Call your server to set up the transaction
         createOrder: function () {
           return fetch('/your-server/paypal/order', {
            method: 'post'
          }).then(function(res) {
              return res.json();
          }).then(function(orderData) {
            orderId =;
            return orderId;

         styles: {
           '.valid': {
            'color': 'green'
           '.invalid': {
            'color': 'red'

         fields: {
           number: {
             selector: "#card-number",
             placeholder: "4111 1111 1111 1111"
           cvv: {
             selector: "#cvv",
             placeholder: "123"
           expirationDate: {
             selector: "#expiration-date",
             placeholder: "MM/YY"
       }).then(function (cardFields) {
         document.querySelector("#card-form").addEventListener('submit', (event) => {

             // Cardholder's first and last name
             cardholderName: document.getElementById('card-holder-name').value,
             // Billing Address
             billingAddress: {
               // Street address, line 1
               streetAddress: document.getElementById('card-billing-address-street').value,
               // Street address, line 2 (Ex: Unit, Apartment, etc.)
               extendedAddress: document.getElementById('card-billing-address-unit').value,
               // State
               region: document.getElementById('card-billing-address-state').value,
               // City
               locality: document.getElementById('card-billing-address-city').value,
               // Postal Code
               postalCode: document.getElementById('card-billing-address-zip').value,
               // Country Code
               countryCodeAlpha2: document.getElementById('card-billing-address-country').value
           }).then(function () {
             fetch('/your-server/api/order/' + orderId + '/capture/', {
               method: 'post'
             }).then(function(res) {
                return res.json();
             }).then(function (orderData) {
                // 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

                // This example reads a v2/checkout/orders capture response, propagated from the server
                // You could use a different API or structure for your 'orderData'
                var errorDetail = Array.isArray(orderData.details) && orderData.details[0];

                if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
                  return actions.restart(); // Recoverable state, per:

                if (errorDetail) {
                    var msg = 'Sorry, your transaction could not be processed.';
                    if (errorDetail.description) msg += '\n\n' + errorDetail.description;
                    if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
                    return alert(msg); // Show a failure message

                // Show a success message or redirect
                alert('Transaction completed!');
          }).catch(function (err) {
            alert('Payment could not be captured! ' + JSON.stringify(err))
     } else {
       // Hides card fields if the merchant isn't eligible
       document.querySelector("#card-form").style = 'display: none';


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.
  • 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}.
  1. 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.
  1. Change BN-Code to your PayPal Partner Attribution ID.
  2. Set intent to capture to immediately capture funds.
  3. 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.
  4. The CSS file in the <head> section is a sample for demo purposes. Instead, you should use styles that match your web site's branding.


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 must 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:

"processor_response": {
    "avs_code": "Y",
    "cvv_code": "S",
    "payment_advice_code": "",
    "response_code": "0000"

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.

curl -v -X POST<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


API response handling