availability

UnionPay is currently in beta and is only available to EU merchants. To request beta access, contact our Accounts team.

Checkout form

Dual-branded cards

Dual-branded cards include both the UnionPay logo and another card brand logo – such as Visa, Mastercard, or American Express – and can be processed through either brand's network. If your business is based outside of China, card network rules around dual-branded UnionPay cards dictate that your customers must be able to select which card brand they want their transaction to process through at checkout.

To maintain compliance with this rule, make sure to include an option in your checkout form for customers to select UnionPay as their card brand. You should only process UnionPay cards directly via the UnionPay network if the customer specifies that they want the card processed this way. Otherwise, dual-branded cards should be processed via the other card brand network.

Card capabilities

UnionPay cards can either be credit or debit. This capability determines what information you will need to collect in your checkout form, as well as your options for processing the transaction on your server:

  • Credit cards
    • Require CVV and expiration date
    • Support both immediate and delayed settlement – you can either submit the transaction for settlement upon creation or make a separate submit for settlement call
  • Debit cards
    • Do not always require CVV or expiration date
    • Support only immediate settlement

Setup

If you are using script tags to load files, be sure to at least include:

HTML
Click to copy
Copied
<script src="https://js.braintreegateway.com/web/3.22.2/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.22.2/js/unionpay.min.js"></script>

UnionPay only supports authorization via client tokens.

Check card capabilities

Use the card number to check the card capabilities. This should be done as soon as the customer has finished entering the card number, since you may need to update your form based on the response:

JavaScript
Click to copy
Copied
var numberField = document.querySelector('#card-number-field');

braintree.client.create({
  authorization: 'CLIENT_TOKEN_FROM_SERVER'
}, function (clientErr, clientInstance) {
  if (clientErr) {
    console.error('Error creating client:', clientErr);
    return;
  }

  // Create a UnionPay component
  braintree.unionpay.create({
    client: clientInstance
  }, function (unionpayErr, unionPayInstance) {
    if (unionpayErr) {
      console.error('Error creating unionPay:', unionpayErr);
      return;
    }

    // Fetch card capabilities when customer has finished entering card number
    numberField.addEventListener('blur', function (event) {
      fetchCapabilities(unionPayInstance);
    }, false);
  });
});

function fetchCapabilities(unionPay) {
  unionPay.fetchCapabilities({
    card: {
      number: numberField.value
    }
  }, function (err, cardCapabilities) {
    if (err) {
      console.error('Error fetching card capabilities:', err);
      return;
    }

    // Determines if the card is UnionPay
    if (cardCapabilities.isUnionPay) {
      if (cardCapabilities.unionPay && !cardCapabilities.unionPay.isSupported) {
        // This UnionPay card cannot be processed by Braintree.
        // Ask the customer to try a different card
      }

      if (cardCapabilities.isDebit) {
        // CVV and expiration date fields not required
      } else {
        // CVV and expiration date fields required
      }

      // Show mobile phone number field
    }
  });
}

Enrollment and tokenization

UnionPay cards require enrollment before they can be tokenized. The enrollment process may require customer action, where UnionPay sends an authorization code via SMS to the customer's mobile phone number. Your integration then collects the SMS auth code from the customer and provides it to us to tokenize the card.

If the enrollment indicates that the SMS code is not required, you can tokenize it immediately.

note

When an enrollment is completed for a UnionPay card, you will no longer be able to update the card number, expiration date, expiration month, or expiration year.

Begin by collecting the card details and customer's mobile phone number:

JavaScript
Click to copy
Copied
unionPay.enroll({
  card: {
    number: '6211111111111111',
    expirationMonth: '12',
    expirationYear: '2038'
  },
  mobile: {
    countryCode: '62',
    number: '11111111111'
  }
}, function (err, response) {
  if (response.smsCodeRequired) {
    // Customer will be sent an SMS code.
    // Show UI for collecting that SMS code.
  } else {
    // SMS code not sent or required.
    // Tokenization can happen immediately.
    unionPay.tokenize(...);
  }
  // ...
});

When attempting to enroll a UnionPay card, it is your responsibility to provide it with the enrollment ID and (if required) the SMS auth code collected from the customer during tokenization:

JavaScript
Click to copy
Copied
unionPay.enroll({
  card: {
    number: '6211111111111111',
    expirationMonth: '12',
    expirationYear: '2038'
  },
  mobile: {
    countryCode: '62',
    number: '11111111111'
  }
}, function(err, response) {
  if (err) {
    console.error('Error during enroll:', err);
    return;
  }

  if (response.smsCodeRequired) {
    // Customer will be sent an SMS code.
    // Get SMS auth code from customer input
    waitForAuthCodeFromCustomer(function (smsAuthCode) {
      // Include the SMS auth code and enrollment ID when tokenizing
      unionPay.tokenize({
       card: {
          number: '6211111111111111',
          expirationMonth: '12',
          expirationYear: '2038',
          cvv: '123'
        },
        smsCode: smsAuthCode,
        enrollmentId: response.enrollmentId
      }, function (err, nonce) {
        // Handle tokenization result.
      });
    });
  } else {
    // SMS code not sent or required.
    // Include the enrollment ID when tokenizing
    unionPay.tokenize({
     card: {
        number: '6211111111111111',
        expirationMonth: '12',
        expirationYear: '2038',
        cvv: '123'
      },
      enrollmentId: response.enrollmentId
    }, function (err, nonce) {
      // Handle tokenization result.
    });
  });
}
});
note

Validating UnionPay is performed during the enrollment process. As such, there is no extra validation process that can be performed during tokenization and the validate property should not be passed when tokenizing a UnionPay card.

UnionPay with Hosted Fields

For a SAQ A PCI compliant UnionPay integration, you can use our Hosted Fields form to collect card information. By using UnionPay with Hosted Fields, you can use the same form for both UnionPay and traditional credit cards.

This guide includes a basic Hosted Fields integration. For more information about configuration and styling, see our Hosted Fields guide.

Create your components

To set up a UnionPay with Hosted Fields integration, you create two separate Hosted Fields and UnionPay components.

For your form, create containers for each field that will be passed in upon creation of your Hosted Fields component. You will need to provide your own inputs to collect the mobile country code, mobile number, and SMS auth code. Because this data does not fall under PCI scope, they do not need to be collected using Hosted Fields.

HTML
Click to copy
Copied
<form action="/" id="my-form" method="post">
  <label for="card-number">Card Number</label>
  <div id="card-number"></div>

  <label for="expiration-date">Expiration Date</label>
  <div id="expiration-date"></div>

  <label for="cvv">CVV</label>
  <div id="cvv"></div>

  <label for="postal-code">Postal Code</label>
  <div id="postal-code"></div>

  <span id="unionpay" hidden>
    <label id="country-code-label" for="country-code">Country Code</label>
    <input id="country-code" type="text" name="country-code" placeholder="62">

    <label id="mobile-number-label" for="mobile-number">Mobile Phone Number</label>
    <input id="mobile-number" type="text" name="mobile-number" placeholder="1111111111">

    <label id="sms-code-label" for="sms-code">SMS Auth Code</label>
    <input id="sms-code" type="text" name="sms-code" placeholder="11111">

    <button type="button" id="enroll-button">Verify</button>
  </span>

  <input disabled type="submit" value="Submit Transaction">
</form>
JavaScript
Click to copy
Copied
braintree.client.create({authorization: 'CLIENT_TOKEN_FROM_SERVER'}, function (err, clientInstance) {
  braintree.hostedFields.create({
    client: clientInstance,
    fields: {
      number: {selector: '#card-number'},
      expirationDate: {selector: '#expiration-date'},
      cvv: {selector: '#cvv'},
      postalCode: {selector: '#postal-code'}
    }
  }, function (hostedFieldsErr, hostedFieldsInstance) {
    braintree.unionpay.create({client: clientInstance}, function (unionPayErr, unionpayInstance) {
      // This is where you will collect UnionPay data
    });
  });
});

Getting card capabilities

You must fetch the capabilities of a card to determine which information is necessary to process it. In your flow, call fetchCapabilities once the customer has provided a valid card number in the number field. You can use the events emitted by Hosted Fields to determine when a user has entered a card number.

JavaScript
Click to copy
Copied
// This occurs inside of the Hosted Fields `create` callback
braintree.unionpay.create({client: clientInstance}, function (unionPayErr, unionpayInstance) {

  hostedFieldsInstance.on('validityChange', function (event) {
    if (!(event.emittedBy === 'number' && event.fields.number.isValid)) {
      return;
    }

    unionpayInstance.fetchCapabilities({ hostedFields: hostedFieldsInstance }, function (fetchErr, cardCapabilities) {
      if (fetchErr) { throw fetchErr; }

      if (cardCapabilities.isUnionPay) {
        if (cardCapabilities.isDebit) {
          // CVV and expiration date fields are not required for all UnionPay debit cards.
          // Indicate that these fields are optional on your form.
        }

        // Show your own mobile phone number inputs for enrollment

        if (cardCapabilities.unionPay && !cardCapabilities.unionPay.isSupported) {
          // This UnionPay card cannot be processed by Braintree.
          // Ask the customer to try a different card.
        }
      }
    });
  });
});

Enrollment

You can enroll using your Hosted Fields instance and the mobile data you've collected.

JavaScript
Click to copy
Copied
// This occurs inside of the Hosted Fields `create` callback
braintree.unionpay.create({client: clientInstance}, function (unionpayErr, unionpayInstance) {
  var enrollButton = document.querySelector('#enroll-button'); // Button to enroll in UnionPay
  var unionpayEnrollmentId;

  hostedFieldsInstance.on('validityChange', function (event) {
    if (event.emittedBy === 'number' && event.fields.number.isValid) {
      // Card is valid; fetch capabilities...
    }
  });

  enrollButton.addEventListener('click', function (event) {
    event.preventDefault();

    unionpayInstance.enroll({
      hostedFields: hostedfieldsInstance,
      // Collect these values using your own inputs
      mobile: {
        countryCode: '62',
        number: '11111111111'
      }
    }, function (enrollErr, enrollData) {
      if (enrollErr) { throw enrollErr; }

      unionpayEnrollmentId = enrollData.enrollmentId;

      if (enrollData.smsCodeRequired) {
        // Show input to collect SMS auth code sent to customer during enrollment
      } else {
        // SMS auth code not required, proceed to tokenize
      }
    });
  }, false);
});

Tokenization

When using UnionPay with Hosted Fields, your method of tokenization depends on the requirements of the card.

If the card is a UnionPay card that requires enrollment, you will tokenize using your UnionPay instance, the enrollmentId you received from your enroll call, and (if required) the smsCode received by the customer on their mobile phone after enrollment.

JavaScript
Click to copy
Copied
unionpayInstance.tokenize({
  hostedFields: hostedFieldsInstance,
  enrollmentId: unionpayEnrollmentId,
  smsCode: '11111' // Only required if smsCodeRequired. Can be left blank or undefined otherwise.
}, function (err, unionpayTokenizeData) {
  if (err) { throw err; }

  // Submit unionpayTokenizeData.nonce to your server
});

If the card is not a UnionPay card you will tokenize using your Hosted Fields instance to retrieve your nonce.

JavaScript
Click to copy
Copied
hostedFieldsInstance.tokenize(function (err, hostedFieldsTokenizeData) {
  if (err) { throw err; }

  // Submit hostedFieldsTokenizeData.nonce to your server
});

Below is a full example of a UnionPay with Hosted Fields tokenization flow:

JavaScript
Click to copy
Copied
// This occurs inside of the Hosted Fields `create` callback
braintree.unionpay.create({client: clientInstance}, function (unionpayErr, unionpayInstance) {
  var enrollButton = document.querySelector('#enroll-button'); // Button to enroll in UnionPay
  var submitButton = document.querySelector('input[type="submit"]'); // Button to submit your form
  var isUnionPay; // Obtained during fetch capabilities
  var unionpayEnrollmentId; // Obtained during enroll

  hostedFieldsInstance.on('validityChange', function (event) {
    if (event.emittedBy === 'number' && event.fields.number.isValid) {
      // Card is valid; fetch capabilities...
    }
  });

  enrollButton.addEventListener('click', function (event) {
    // Enrollment if applicable...
  }, false);

  submitButton.addEventListener('click', function (event) {
    event.preventDefault();

    if (isUnionPay) {
      // Tokenize with UnionPay, using Hosted Fields instance
      unionpayInstance.tokenize({
        hostedFields: hostedFieldsInstance,
        enrollmentId: unionpayEnrollmentId,
        smsCode: '11111' // Only required if smsCodeRequired. Can be left blank or undefined otherwise.
      }, function (unionpayTokenizeErr, unionpayTokenizeData) {
        if (unionpayTokenizeErr) { throw unionpayTokenizeErr; }

        // Submit unionpayTokenizeData.nonce to your server
      });
    } else {
      // Tokenize with Hosted Fields
      hostedFieldsInstance.tokenize(function (hostedFieldsTokenizeErr, hostedFieldsTokenizeData) {
        if (hostedFieldsTokenizeErr) { throw hostedFieldsTokenizeErr; }

        // Submit hostedFieldsTokenizeData.nonce to your server
      });
    }
  }, false);
});

You can find out more about UnionPay in the JavaScript SDK v3 reference.

Special considerations

AVS and CVV validation does not apply

AVS and CVV validation does not apply to UnionPay cards, since the enrollment process handles card validation. Any AVS and CVV rules you've enabled for credit cards will be ignored for UnionPay cards.

Next: Server-side →

Still have questions?

If you can’t find an answer, contact our Support team.