Tutorial Scope
We will address the 3DS flow specifics of creating a subscription in Chargebee using Braintree’s Hosted Fields, integrated through Braintree.js and Chargebee APIs. We have also included the example code and Github links to it. This way, you can try out the tutorial with our mock checkout.
Braintree.js: Overview
Braintree.js is a JavaScript library, which is made accessible via APIs to tokenize customer information by collecting sensitive card data using customizable Braintree Hosted Fields. For further details, take a look at Braintree's documentation.
Steps: Overview
Here's a detailed set of steps on how the Braintree.js & Chargebee 3DS checkout flow works:
- After the customer is led to the checkout page, a unique client token is embedded into the checkout page (this unique client token needs to be generated from the server using Braintree's SDK).
- When the customer submits the payment form, Braintree encrypts the card information and returns it as a payment method nonce(temporary token).
- This payment method nonce is then used to perform 3DS verification, which returns a 3DS-verified nonce.
- The 3DS-verified nonce is then passed to Chargebee along with the other parameters, to create a subscription using the create subscription API.
Honey Comics - Demo Application
Honeycomics is Chargebee’s demo application. You can download its code and create the application to test out the flow mentioned in this tutorial.
Prerequisites
Before trying out this tutorial, you need to setup the following:
- A Chargebee account. Signup for a free trial if you don't have one.
- Plans configured in Chargebee.
- Braintree sandbox account integrated with your Chargebee user interface. Learn more
- Braintree SDK set up in your server.
- Your Chargebee test site's API key.
Client Side Implementation
Step 1: Build the checkout form
The client side implementation starts by building a form for users to sign up. The sample form we've used here contains fields for customer and card information.
The form snippet below shows customer detail fields. In this case the name attribute is set, and has to be passed to Chargebee demo application’s server.
<div className="col-sm-6">
<div className="form-group">
<label for="customer[email]">Email</label>
<input id="email" type="text" className="form-control" name="customer[email]" maxlength="50"
data-rule-required="true" data-rule-email="true"
data-msg-required="Please enter your email address"
data-msg-email="Please enter a valid email address">
<small for="customer[email]" className="text-danger"></small>
</div>
</div>
Step 2: Integrate Braintree.js
Now that the form is built, integrate Braintree.js into the checkout form by adding it to the checkout page’s header tag.
<script src="https://js.braintreegateway.com/web/3.29.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.29.0/js/three-d-secure.js"></script>
<script src="https://js.braintreegateway.com/web/3.29.0/js/hosted-fields.js"></script>
Step 3: Estimate Subscription amount
While loading the payment details collection page, call Chargebee’s Estimate API from your server to get the subscription amount.
The amount returned will be in sub-units(cents) and needs to be converted into units(euros). After that, send it to Braintree using the verifyCard function.
var estimateamount;
fetch('/braintree-js-3ds/estimate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
sub_plan_id: 'professional' // provide your plain id
})
}).then(response => response.json()).then(function (responseJSON) {
estimateamount = responseJSON.invoice_estimate.total;
// convert the cents to actual amount since chargebee returns the amount in cents
estimateamount = estimateamount/100;
});
Step 4: Create client token from the server
A Client token has to be embedded into the checkout form. This token is unique and has to be generated from the server using Braintree's SDK.
<script type="text/javascript">
//Replace it with your key
var clientToken = new braintree.api.Client({ clientToken : "<%= getBraintreeClientToken()%>"});
</script>
Step 5: Create components using Client token
Now that you have Client token on your side, create components for temporary nonce and 3DS verification using the code given below:
function onClientCreate(err, client) {
components.client = client;
braintree.hostedFields.create({
client: client,
styles: {
input: {
'font-size': '14px',
'font-family': 'monospace'
}
},
fields: {
number: {
selector: '#number',
placeholder: '4000 0000 0000 002'
},
cvv: {
selector: '#cvv',
placeholder: '123'
},
expirationDate: {
selector: '#date',
placeholder: '01 / 20'
}
}
}, onComponent('hostedFields'));
braintree.threeDSecure.create({
client: client,
version: 2,
}, onComponent('threeDSecure'));
}
function onComponent(name) {
return function (err, component) {
components[name] = component;
}
}
Step 6: Tokenization & Verification
After the customer clicks on submit, you need to send the card details to Braintree and create a temporary token using hostedFields.tokenize() function.
In the callback function, you will get the temporary token. Using the temporary token, send verifyCard() request to Braintree.
Braintree then performs 3DS verification for the card and will respond with the 3DS verified nonce if successful. This nonce can then be passed on to Chargebee’s create subscription API.
When you tokenize a card using Braintree JS, it's crucial to note the parameter authenticationInsight.regulationEnvironment
. If this regulation environment is equal to psd2
, Chargebee mandates the 3DS challenge to avoid failures. To enforce the 3DS challenge and minimize potential failures, you can set the challengeRequested
parameter as true while calling the braintree.threeDSecure.verifyCard
method.
If the card issued does not support 3DS, verification will not happen and Braintree would return an unusable nonce(Not accepted by Chargebee APIs).
components.hostedFields.tokenize(function (err, payload) {
components.threeDSecure.verifyCard({
amount: estimateamount,
nonce: payload.nonce,
addFrame: addFrame,
removeFrame: removeFrame,
onLookupComplete: function (data, next) {
next();
}
}, function (err, payload) {
if ($("input[name='braintreeToken']").length == 1) {
$("input[name='braintreeToken']").val(payload.nonce);
}
else{
form.append("<input type='hidden' name='braintreeToken' value='" + payload.nonce + "' />");
}
var options = {
error: subscribeErrorHandler,
success: subscribeResponseHandler,
complete: hideProcessing,
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
dataType: 'json'
};
$(form).ajaxSubmit(options);
});
});
Server Side Implementation
Setup Chargebee’s Client library
Download and import the client library of your choice. Then, configure the client library with Chargebee Test site and its full-access API Key.
For the tutorials we have configured the site and the credentials in a properties file from which the client library is configured at the webapp is initialized.
/**
* The credentials are stored in a properties file under WEB-INF
* The live site api keys should be stored securely. It should preferably
* be stored only in the production machine(s) and not hard coded
* in code or checked into a version control system by mistake.
*/
Properties credentials = read("WEB-INF/ChargeBeeCredentials.properties");
Environment.configure(credentials.getProperty("site"), credentials.getProperty("api_key"));
For the tutorials we have configured the site credentials in config/environments/development.rb
ENV["CHARGEBEE_SITE"]="honeycomics-test"
ENV["CHARGEBEE_API_KEY"]="test_5LjFA6K6doB2EKRP7cufTd5TvT32a5BrT"
For the tutorials we have configured the site credentials in Config.php which is included in other php files.
require_once(dirname(__FILE__) . "/lib/ChargeBee.php");
/*
* Sets the environment for calling the Chargebee API.
* You need to sign up at ChargeBee app to get this credential.
* It is better if you fetch configuration from the environment
* properties instead of hard coding it in code.
*/
ChargeBee_Environment::configure("honeycomics-test", "test_5LjFA6K6doB2EKRP7cufTd5TvT32a5BrT");
Creating a subscription
To create a subscription in Chargebee, the 3DS-verified nonce fetched earlier has to be passed along with the other POST parameters (from the checkout page's form submit event) using the create subscription API.
String planId = "professional"; // replace your plan id
Result result = Subscription.create()
.planId(planId)
.customerFirstName(request.getParameter("customer[first_name]"))
.customerLastName(request.getParameter("customer[last_name"))
.customerEmail(request.getParameter("customer[email]"))
.customerPhone(request.getParameter("customer[phone]"))
.paymentIntentGatewayAccountId("<braintree-gateway-account-id>")
.paymentIntentGwToken(request.getParameter("braintreeToken"))
.request();
# Creating a subscription in ChargeBee by passing the encrypted
# card number and card cvv provided by Braintree Js.
create_subscription_params = {:plan_id => plan_id,
:customer => params['customer'],
:card => {"tmp_token" => params['braintreeToken'] }}
result = ChargeBee::Subscription.create(create_subscription_params)
/* Creating a subscription in ChargeBee by passing the encrypted
* card number and card cvv provided by Braintree Js.
*/
$createSubscriptionParams = array(
"planId" => $planId,
"customer" => $body['customer'],
"payment_intent" => array(
"gw_token" => $body['braintreeToken'],
"gateway_account_id" => "<braintree_gateway_account_id>"
)
);
$result = ChargeBee_Subscription::create($createSubscriptionParams);
Though the parameters have been validated at the client side, for additional security, we strongly recommend that you perform these validations on the server side as well.
For demonstrative purposes, we have skipped validating the parameters on the server's side.
Chargebee response:
- Chargebee returns a success response in the JSON format which is wrapped in the form of a 'result' class by the client library.
- In case of an error, Chargebee returns an error response which is an exception thrown by the client library.
In case of successful checkout, you can redirect the user to a simple 'Thank You' page.
Validation and Error Handling :
Here's how we validate user inputs and handle API call errors in this demo:
- Client Side Validation: Chargebee uses jQuery form validation plugin to check whether the user's field inputs(email, zip code and phone number) are valid or not.
- Server Side Validation: As this is a demo application we have skipped the server side validation of all input parameters. But we recommend you to perform the validation at your end.
- Payment Errors: If a payment fails due to card verification or processing errors, Chargebee returns an error response which is thrown as a payment exception by the client library. Exceptions are handled in the demo application with appropriate error messages.
- General API Errors: Chargebee might return error responses due to various reasons such as invalid configuration, bad request etc. To identify specific reasons for all error responses you can check the API documentation. Also take a look at the error handler file to check how these errors can be handled.
Test cards
When you're all set, test your integration with some test transactions. Here are some credit card numbers that you can use to test the application:
Visa | 4000 0000 0000 0002 |
Mastercard | 5555 5555 5555 4444 |
American Express | 3782 822463 10005 |
For more test cards for testing different scenarios click here.
Reference Links
We're always happy to help you with any questions you might have!
support@chargebee.com