This is the older version of the Payment Request API (W3C). Information on the previous version is available here.
The Payment Request API is a W3C standard that eliminates checkout forms by creating a fast, simple, and consistent payment experience for shoppers using supported browsers. Using this solution, BlueSnap securely captures and tokenizes the shopper’s data obtained from the browser, allowing you to process card payments with our Payment API while keeping your PCI burden to a minimum. This solution is especially useful for streamlining guest checkouts and minimizing friction for returning shoppers who want to pay with a new card. The shopper selects a saved payment method and confirms the purchase in the payment UI provided by the browser.
This guide covers the following topics:
Try it now
Use a supported browser to try it below. Your card will not be charged. If you would rather add a test card, you can use this one: ccn: 4263982640269299, exp: 02/2023, and cvv: 837.
Supported browsers
Visit caniuse.com for the latest list of supported browsers.
Prerequisites
- Make sure your website is served over HTTPS.
- Have a traditional checkout form (that uses Hosted Payment Fields, for example) that you can display if the shopper is not using a supported browser or if they don't have a supported card.
Use Hosted Payment Fields to minimize your PCI burden
We recommend using Hosted Payment Fields in addition to the Payment Request API to keep your PCI to the minimum SAQ-A.
Implementing the Payment Request API
Step 1: Obtain a token for the session
Obtain a token for the session by sending a server-to-server POST request to the URL of the relevant environment:
- Sandbox: https://sandbox.bluesnap.com/services/2/payment-fields-tokens
- Production: https://ws.bluesnap.com/services/2/payment-fields-tokens
The token is returned in the Location header in the response, as shown below. For more details, click here.
location: https://sandbox.bluesnap.com/services/2/payment-fields-tokens/cfa6cc68b844861a660ac31b7715b7bc704e092500005aebfa3d48e665ecece6_
Step 2: Add the BlueSnap JavaScript file to your page
Add the following BlueSnap JavaScript file to your page and replace {BlueSnap domain}
with the relevant domain for Sandbox (https://sandbox.bluesnap.com) or Production (https://ws.bluesnap.com).
<script src="{BlueSnap domain}/source/web-sdk/bluesnap.js"></script>
Step 3: Create the PaymentRequest instance
Check to make sure the shopper's browser supports the Payment Request API using bluesnap.isSupported('PaymentRequest')
. If so, create a new PaymentRequest
instance by calling bluesnap.paymentRequest
with these arguments:
token
- The token you created in Step 1.function(instance) {...}
- A callback function that BlueSnap invokes after the instance is created.
If the Payment Request API is not supported, it is recommended to set up a traditional checkout flow that uses BlueSnap's Hosted Payment Fields.
if (bluesnap.isSupported('PaymentRequest')) {
// Browser supports the Payment Request API
// Create a new PaymentRequest instance
var paymentRequest;
bluesnap.paymentRequest(token, function(instance) {
paymentRequest = instance;
});
} else {
// Browser doesn't support the Payment Request API
// Set up traditional checkout flow
}
Step 4: Add a div element to your page
Add the following <div>
element to your page that BlueSnap will use to hold the iFrame containing the hidden Payment Request button.
<div data-bluesnap="PaymentRequest"></div>
Step 5: Initialize the PaymentRequest instance
Initialize paymentRequest
by calling its init
method with these arguments:
detailsObj
- The object that holds data about the transaction (such as the transaction total) that will tell the browser what to display in the payment UI, among other things (see Deep dive into defining detailsObj).attValue
- The value of thedata-bluesnap
attribute from Step 4 so BlueSnap will know where to hold the iFrame.
paymentRequest.init({
details: {
total: {
label: 'Total',
amount: {currency: 'USD', value: '100.00'}
}
}
}, 'PaymentRequest')
.then(function() {
// Initialization was successful
})
.catch(function(err) {
// Initialization failed
console.log(err);
});
Step 6: Show the Payment Request button
Check whether the shopper has saved a supported card using canMakePayment()
. If they have one present, call showButton()
to display the button that BlueSnap provides, which, when clicked, will show the payment UI provided by the browser. If the shopper doesn't have a supported card, it is recommended to set up a traditional checkout flow.
paymentRequest.canMakePayment()
.then(function(result) {
if (result) {
// The shopper has a supported card
// Show the Payment Request button
paymentRequest.showButton()
.then(...).catch(...); // Continued in Step 7
} else {
// The shopper doesn't have a supported card
// Set up traditional checkout flow
}
})
.catch(function(err) {
console.log(err);
// Either call showButton() or fallback to traditional checkout flow
});
If you would rather use your own button to show the payment UI:
Click here to learn how.
Step 7: Process the payment using the token
Calling showButton()
will display the payment UI to the shopper. The shopper will either close the payment UI (causing the promise to reject) or successfully confirm the purchase (causing the promise to resolve), at which time, you'll need to send the token to your server and process the transaction using the Payment API (click here for code samples). Once you receive the response from BlueSnap, you'll need to communicate the result with the browser by calling complete
with either 'success' or 'fail', prompting the browser to close the payment UI or display an error message.
// Continued from above
paymentRequest.showButton()
.then(function(ev) {
// The shopper confirmed the purchase
// Send ev.token to your server and process the transaction...
// ... Report the transaction result to the browser
ev.complete('success'); // or ev.complete('fail');
})
.catch(function(err) {
// The shopper closed the payment UI
console.log(err);
});
Once the callback function triggers, you can then process payments by including the Payment Request API (W3C) token in your API requests. This must be done from your server and requires using your API Credentials.
For more information, refer to Completing Tokenized Payments
Additional topics
Deep dive into defining detailsObj
Including the following properties within detailsObj
allows you to tell the browser exactly what it should display in the payment UI, define what details it should collect from the shopper (such as email and phone), and specify the cards that you support on your website.
Property | Type | Required | Description |
---|---|---|---|
details | object | Required | Allows you to define the transaction total, display line items, and shipping options that the browser should display in the payment UI. At a minimum, the total must be included. (To learn how to handle shipping, see Collecting shipping information.) |
options | object | Optional | Allows you to indicate whether email, name, phone, or shipping address should be collected from the shopper in the payment UI. By default, these details are not collected. |
methodData | array | Optional | Allows you to tell the browser which cards are supported on your website (as long as those cards are enabled for your BlueSnap configuration). By default, all cards that are enabled for your BlueSnap configuration are supported. (To learn how to enable or disable certain cards in the BlueSnap Console, click here.) |
detailsObj example
var detailsObj = {
details: {
displayItems: [
{
label: 'Subtotal',
amount: {currency: 'USD', value: '100.00'}
},
{
label: 'Tax',
amount: {currency: 'USD', value: '5.50'}
}
],
total: {
label: 'Total',
amount: {currency: 'USD', value: '105.50'}
},
shippingOptions: [{
id: 'standard',
label: 'Standard shipping',
amount: {currency: 'USD', value: '0.00'},
selected: true // Standard shipping will be selected by default in the payment UI
}]
},
options: {
requestPayerEmail: true,
requestPayerName: true,
requestPayerPhone: true,
requestShipping: true
},
methodData: [{
supportedMethods: 'basic-card',
data: {
supportedNetworks: ['mastercard', 'visa'],
supportedTypes: ['debit', 'credit']
}
}]
};
Collecting shipping information
Step 1: Tell the browser to collect the shopper's shipping address
If you sell physical goods that need to be shipped, tell the browser to collect the shopper's shipping address in the payment UI. Do this by including requestShipping: true
within options
when you initialize paymentRequest
. If the shipping options don't depend on the shopper's address (for example, you offer free, worldwide shipping), you may also want to provide shippingOptions
at this time.
paymentRequest.init({
details: {
total: {
label: "Total",
amount: {currency: 'USD', value: '100.00'}
},
// Optional: Include shipping options
shippingOptions: [{
id: 'standard',
label: 'Free shipping',
amount: {currency: 'USD', value: '0.00'},
selected: true // Free shipping will be selected by default in the payment UI
}]
},
options: {
// Required: Tell browser to request shipping address
requestShipping: true
}
}, 'PaymentRequest')
.then(...).catch(...);
Step 2: Handle shipping address changes
Listen to the shippingaddresschange
event to know when the shopper selects a shipping address, providing you the opportunity to verify that the address meets your requirements and to determine the available shipping options. To update the payment UI, call updateWith
with the available shipping options or an error, depending on whether the shopper's address meets your requirements. If no changes need to be made to the payment UI, call noChange()
.
paymentRequest.on('shippingaddresschange', function(ev) {
if (ev.shippingAddress.country !== 'US') {
// Shipping address is invalid since merchant doesn't ship outside the US
// Update payment UI with an error
ev.updateWith({
total: {
label: 'Total',
amount: {currency: 'USD', value: '100.00'}
},
error: 'Can only ship to the US'
});
} else {
// Shipping address is valid
// Fetch shipping options from server...
//... return shipping options
// For example:
var availableShippingOptions = [
{
id: 'standard',
label: 'Standard shipping',
amount: {currency: 'USD', value: '0.00'}
},
{
id: 'express',
label: 'Express shipping',
amount: {currency: 'USD', value: '10.00'}
}
];
// Update payment UI
ev.updateWith({
total: {
label: 'Total',
amount: {currenty: 'USD', value: '100.00'}
},
shippingOptions: availableShippingOptions
});
}
});
Step 3: Handle shipping options changes
Listen to the shippingoptionchange
event to know when the shopper selects a shipping option, providing you the opportunity to mark the shipping option as selected
and to update the total and display items. Similiar to the previous step, call updateWith
with the updated details (or call noChange
if no changes to the payment UI are required).
paymentRequest.on('shippingoptionchange', function(ev) {
// Get the ID of the selected shipping option
var selectedId = ev.shippingOption;
// Mark option as selected
var selectedShippingOption;
availableShippingOptions.forEach(function(option) {
option.selected = (option.id === selectedId);
if (option.id === selectedId) {
selectedShippingOption = option;
}
});
// Update display items and total
var subtotal = '100.00';
var shippingPrice = selectedShippingOption.amount.value;
var totalAmount = (Number(subtotal) + Number(shippingPrice)).toFixed(2);
var displayItems = [
{
label: 'Subtotal',
amount: {currency: 'USD', value: subtotal}
},
{
label: selectedShippingOption.label,
amount: {currency: 'USD', value: shippingPrice}
}
];
var total = {
label: 'Total',
amount: {currency: 'USD', value: totalAmount}
};
// Update payment UI
ev.updateWith({
displayItems: displayItems,
total: total,
shippingOptions: availableShippingOptions
});
});
Styling the Payment Request button
To style the Payment Request button, create a style
object using the following properties and pass it to showButton()
. To adjust the height and width, style the <div>
element from Step 4. The button's minimum height is 32px, its maximum height is 64px, and its width is always 100%.
var style = {
theme: 'light', // default is 'dark'
text: 'Check out' // default is 'Pay now'
};
paymentRequest.showButton(style)
.then(...).catch(...);
The images below show a few examples of the Payment Request button. The left button has the default appearance. The right button has the light theme with the default text.
Using your own button to show the payment UI
If you would rather use your own button to show the payment UI, use show()
(instead of showbutton()
). This method shows the payment UI to the shopper and returns a promise. The shopper will either close the payment UI (causing the promise to reject) or successfully confirm the purchase (causing the promise to resolve).
When the promise resolves, send the token to your server and process the transaction using the Payment API (click here for code samples). Once you receive the response from BlueSnap, communicate the result with the browser by calling complete
with either 'success' or 'fail', prompting the browser to close the payment UI or display an error message.
paymentRequest.show()
.then(function(ev) {
// The shopper confirmed the purchase
// Send ev.token to your server and process the transaction...
// ... Report the transaction result to the browser
ev.complete('success'); // or ev.complete('fail');
})
.catch(function(err) {
// The shopper closed the payment UI
console.log(err);
});
Possible errors
Code | Description |
---|---|
missing_required_field | Required field {...} is missing |
invalid_value | The value {...} for field {...} is invalid |