{"_id":"5aaab78a7c4f4000128a460d","project":"57336fd5a6a9c40e00e13a0b","version":{"_id":"5aaa8f747ac7ec00910cc228","project":"57336fd5a6a9c40e00e13a0b","__v":1,"createdAt":"2018-03-15T15:21:24.014Z","releaseDate":"2018-03-15T15:21:24.014Z","categories":["5aaa8f747ac7ec00910cc229","5aaa8f747ac7ec00910cc22a","5aaa8f747ac7ec00910cc22b","5aaa8f747ac7ec00910cc22c","5aaa8f747ac7ec00910cc22d","5aaa8f747ac7ec00910cc22e","5aaa8f747ac7ec00910cc22f","5aaa8f747ac7ec00910cc230"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"3.25 Release","version_clean":"8976.0.0-Basics","version":"8976-Basics"},"category":{"_id":"5aaa8f747ac7ec00910cc230","version":"5aaa8f747ac7ec00910cc228","project":"57336fd5a6a9c40e00e13a0b","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-11-03T20:45:01.593Z","from_sync":false,"order":7,"slug":"topics","title":"Guides"},"user":"560d5913af97231900938124","__v":0,"parentDoc":null,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2018-03-15T18:12:26.095Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":12,"body":"The Payment Request API is a [W3C standard](https://www.w3.org/TR/payment-request/) 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](/v8976-JSON/docs) 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.  \n\nThis guide will cover the following topics: \n* [Try it now](#section-try-it-now)\n* [Supported browsers](#section-supported-browsers)\n* [Prerequisites](#section-prerequisites)\n* [Implementing the Payment Request API](#section-implementing-the-payment-request-api)\n* [Additional topics](#section-additional-topics)\n\n## Try it now\nUse a supported browser to try it below. Your card will **not** be charged.\n[block:html]\n{\n  \"html\": \"<script type=\\\"text/javascript\\\" src=\\\"https://sandbox.bluesnap.com/source/web-sdk/bluesnap.js\\\"></script>\\n\\n\\t<div id=\\\"BlueSnapContainer\\\" data-bluesnap=\\\"PaymentRequestButton\\\" style=\\\"width: 150px; height: 40px;\\\"></div>\\n\\t<div id=\\\"notSupportedMessage\\\" style=\\\"display: none;\\\">\\n\\t\\t<p style=\\\"border: 1px solid #cccbcb; border-radius: 5px; padding: 15px; background-color: #f7f7f7;\\\">Your browser does not support the Payment Request API. Switch to one of the supported browsers to try the button.</p>\\n\\t</div>\\n\\n\\t<script>\\n    // Demo Payment Request Button\\n\\t\\t// Note: This code is for demo purposes only\\n\\t\\tif (bluesnap.isSupported('PaymentRequest')) {\\n      console.log(\\\"This browser supports the Payment Request API\\\"); \\n\\t\\t\\tvar paymentRequest;         bluesnap.paymentRequest('a499396a6431e66745d0f762fbe10c05877a8001b5c4e953ed326e6dfa64eea7_', function(instance) {\\n        paymentRequest = instance;\\n\\n\\t\\t\\t\\tvar details = {\\n\\t\\t\\t\\t\\tdetails: {\\n\\t    \\t\\t\\t\\ttotal: {\\n\\t      \\t\\t\\t\\t\\tlabel: \\\"Total (won't be charged)\\\", \\n\\t      \\t\\t\\t\\t\\tamount: {currency: 'USD', value: '12.00'}\\n\\t    \\t\\t\\t\\t}\\n\\t  \\t\\t\\t\\t}\\n  \\t\\t\\t\\t};\\n        \\n\\t\\t\\t\\tpaymentRequest.init(details, 'PaymentRequestButton').then(function() {\\n\\t\\t\\t\\t\\tpaymentRequest.showButton().then(function(ev) {\\n\\t  \\t\\t\\t\\t\\tconsole.log(\\\"The shopper approved the payment\\\");\\n\\t  \\t\\t\\t\\t\\tev.complete('success').then(function(result) {\\n\\t  \\t\\t\\t\\t\\t\\tlocation.reload();\\n\\t  \\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t\\t})\\n\\t\\t\\t\\t\\t.catch(function(e) {\\n\\t\\t\\t\\t\\t\\tconsole.log(\\\"The shopper closed the payment UI\\\");\\n\\t\\t\\t\\t\\t\\tlocation.reload();\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t});\\n\\t\\t\\t});\\n\\t\\t}\\n\\t\\telse {\\n      console.log(\\\"This browser does not support the Payment Request API\\\"); \\n      document.getElementById(\\\"BlueSnapContainer\\\").style.display = \\\"none\\\"; \\n\\t\\t\\tdocument.getElementById(\\\"notSupportedMessage\\\").style.display=\\\"block\\\";\\n\\t\\t}\\n\\t</script>\"\n}\n[/block]\n## Supported browsers \nVisit <a href=\"https://caniuse.com/#feat=payment-request\" target=\"_blank\">caniuse.com</a> for the latest list of supported browsers.\n\n## Prerequisites\n* Make sure your website is served over HTTPS.\n* Have a traditional checkout form (that uses [Hosted Payment Fields](/v8976-Tools/docs/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. \n<br>\n[block:callout]\n{\n  \"type\": \"success\",\n  \"title\": \"Use Hosted Payment Fields to minimize your PCI burden\",\n  \"body\": \"We recommend using [Hosted Payment Fields](/v8976-Tools/docs/hosted-payment-fields) in addition to the Payment Request API to keep your PCI to the minimum SAQ-A.\"\n}\n[/block]\n# Implementing the Payment Request API\n\n### Step 1: Obtain a token for the session\nObtain a token for the session by sending a server-to-server POST request to the URL of the relevant environment: \n\n* **Sandbox:** <span>https://</span>sandbox.bluesnap.com/services/2/payment-fields-tokens\n* **Production:** <span>https://</span>ws.bluesnap.com/services/2/payment-fields-tokens\n\nThe token is returned in the Location header in the response, as shown below. For more details, click [here](/v8976-Tools/docs/create-hosted-payment-fields-token).  \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"location: https://sandbox.bluesnap.com/services/2/payment-fields-tokens/cfa6cc68b844861a660ac31b7715b7bc704e092500005aebfa3d48e665ecece6_\",\n      \"language\": \"curl\",\n      \"name\": \"Sandbox response example\"\n    }\n  ]\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>\n\n### Step 2: Add the BlueSnap JavaScript file to your page  \nAdd the following BlueSnap JavaScript file to your page and replace `{BlueSnap domain}` with the relevant domain for Sandbox (<span>https://</span>sandbox.bluesnap.com) or Production (<span>https://</span>ws.bluesnap.com).\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script src=\\\"{BlueSnap domain}/source/web-sdk/bluesnap.js\\\"></script>   \",\n      \"language\": \"html\"\n    }\n  ]\n}\n[/block]\n### Step 3: Create the PaymentRequest instance\nCheck 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: \n* `token` - The token you created in Step 1. \n* `function(instance) {...}` - A callback function that BlueSnap invokes after the instance is created. \n\nIf the Payment Request API is not supported, it is recommended to set up a traditional checkout flow that uses BlueSnap's [Hosted Payment Fields](/v8976-Tools/docs/hosted-payment-fields). \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if (bluesnap.isSupported('PaymentRequest')) {\\n  // Browser supports the Payment Request API\\n  // Create a new PaymentRequest instance\\n  var paymentRequest;\\n  bluesnap.paymentRequest(token, function(instance) {\\n    paymentRequest = instance;\\n  });\\n} else {\\n  // Browser doesn't support the Payment Request API\\n  // Set up traditional checkout flow\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>\n\n### Step 4: Add a div element to your page\nAdd the following `<div>` element to your page that BlueSnap will use to hold the iFrame containing the hidden Payment Request button.    \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<div data-bluesnap=\\\"PaymentRequest\\\"></div>\",\n      \"language\": \"html\"\n    }\n  ]\n}\n[/block]\n### Step 5: Initialize the PaymentRequest instance\nInitialize `paymentRequest` by calling its `init` method with these arguments: \n* `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](#section-deep-dive-into-defining-detailsobj)).\n* `attValue` - The value of the `data-bluesnap` attribute from Step 4 so BlueSnap will know where to hold the iFrame. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"paymentRequest.init({\\n  details: {\\n    total: {\\n      label: 'Total', \\n      amount: {currency: 'USD', value: '100.00'}\\n    }\\n  }\\n}, 'PaymentRequest') \\n.then(function() {\\n  // Initialization was successful \\n})\\n.catch(function(err) {\\n  // Initialization failed\\n  console.log(err); \\n}); \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>\n\n### Step 6: Show the Payment Request button\nCheck 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. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"paymentRequest.canMakePayment()\\n.then(function(result) {\\n  if (result) {\\n    // The shopper has a supported card \\n    // Show the Payment Request button \\n    paymentRequest.showButton()\\n    .then(...).catch(...); // Continued in Step 7\\n  } else {\\n    // The shopper doesn't have a supported card \\n    // Set up traditional checkout flow  \\n  }\\n})\\n.catch(function(err) {\\n  console.log(err); \\n  // Either call showButton() or fallback to traditional checkout flow\\n}); \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"If you would rather use your own button to show the payment UI:\",\n  \"body\": \"Click [here](#section-using-your-own-button-to-show-the-payment-ui) to learn how.\"\n}\n[/block]\n### Step 7: Process the payment using the token\nCalling `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](/v8976-Tools/docs/hosted-payment-fields#section-in-the-payment-api) 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.   \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Continued from above\\npaymentRequest.showButton()\\n.then(function(ev) {\\n  // The shopper confirmed the purchase \\n  // Send ev.token to your server and process the transaction...\\n      \\n  // ... Report the transaction result to the browser\\n  ev.complete('success'); // or ev.complete('fail');\\n}) \\n.catch(function(err) {\\n  // The shopper closed the payment UI\\n  console.log(err); \\n});   \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>\n\n# Additional topics\n## Deep dive into defining detailsObj\nIncluding 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.\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Property\",\n    \"h-1\": \"Type\",\n    \"h-2\": \"Required\",\n    \"h-3\": \"Description\",\n    \"0-0\": \"`details`\",\n    \"0-1\": \"object\",\n    \"0-2\": \"**Required**\",\n    \"0-3\": \"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](#section-collecting-shipping-information).)\",\n    \"1-0\": \"`options`\",\n    \"1-1\": \"object\",\n    \"1-2\": \"*Optional*\",\n    \"1-3\": \"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.\",\n    \"2-0\": \"`methodData`\",\n    \"2-1\": \"array\",\n    \"2-2\": \"*Optional*\",\n    \"2-3\": \"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](https://support.bluesnap.com/docs/payment-method-setup#section-enable-disable-specific-cards).)\"\n  },\n  \"cols\": 4,\n  \"rows\": 3\n}\n[/block]\n### detailsObj example\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var detailsObj = {\\n  details: {\\n    displayItems: [\\n      {\\n        label: 'Subtotal',\\n        amount: {currency: 'USD', value: '100.00'}\\n      },\\n      {\\n        label: 'Tax',\\n        amount: {currency: 'USD', value: '5.50'}\\n      }\\n    ],\\n    total: {\\n      label: 'Total',\\n      amount: {currency: 'USD', value: '105.50'}\\n    }, \\n    shippingOptions: [{\\n        id: 'standard',\\n        label: 'Standard shipping',\\n        amount: {currency: 'USD', value: '0.00'},\\n        selected: true // Standard shipping will be selected by default in the payment UI\\n    }]\\n  },\\n  options: {\\n    requestPayerEmail: true,\\n    requestPayerName: true,\\n    requestPayerPhone: true,\\n    requestShipping: true\\n  }, \\n  methodData: [{\\n      supportedMethods: 'basic-card',\\n      data: {\\n        supportedNetworks: ['mastercard', 'visa'],\\n        supportedTypes: ['debit', 'credit']\\n      }\\n    }]\\n};\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>\n\n## Collecting shipping information\n### Step 1: Tell the browser to collect the shopper's shipping address\nIf 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. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"paymentRequest.init({\\n  details: {\\n    total: {\\n      label: \\\"Total\\\", \\n      amount: {currency: 'USD', value: '100.00'}\\n    }, \\n    // Optional: Include shipping options\\n    shippingOptions: [{\\n      id: 'standard', \\n      label: 'Free shipping', \\n      amount: {currency: 'USD', value: '0.00'}, \\n      selected: true // Free shipping will be selected by default in the payment UI\\n    }]\\n  }, \\n  options: {\\n    // Required: Tell browser to request shipping address \\n    requestShipping: true\\n  }\\n}, 'PaymentRequest')\\n.then(...).catch(...);\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>\n\n### Step 2: Handle shipping address changes \nListen 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()`. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"paymentRequest.on('shippingaddresschange', function(ev) {\\n  if (ev.shippingAddress.country !== 'US') {\\n    // Shipping address is invalid since merchant doesn't ship outside the US\\n    // Update payment UI with an error\\n    ev.updateWith({\\n      total: {\\n        label: 'Total',\\n        amount: {currency: 'USD', value: '100.00'}\\n      },\\n      error: 'Can only ship to the US'\\n    }); \\n  } else {\\n    // Shipping address is valid\\n    // Fetch shipping options from server...\\n    \\n    //... return shipping options\\n    // For example: \\n    var availableShippingOptions = [ \\n      {\\n        id: 'standard',\\n        label: 'Standard shipping',\\n        amount: {currency: 'USD', value: '0.00'}\\n      },\\n      {\\n        id: 'express',\\n        label: 'Express shipping',\\n        amount: {currency: 'USD', value: '10.00'}\\n      }\\n    ];\\n    \\n    // Update payment UI \\n    ev.updateWith({\\n      total: {\\n        label: 'Total', \\n        amount: {currenty: 'USD', value: '100.00'}\\n      }, \\n      shippingOptions: availableShippingOptions\\n    }); \\n  }\\n}); \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>\n\n### Step 3: Handle shipping options changes \nListen 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). \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"paymentRequest.on('shippingoptionchange', function(ev) {\\n  // Get the ID of the selected shipping option\\n  var selectedId = ev.shippingOption; \\n  \\n  // Mark option as selected\\n  var selectedShippingOption; \\n  availableShippingOptions.forEach(function(option) {\\n    option.selected = (option.id === selectedId);\\n    if (option.id === selectedId) {\\n      selectedShippingOption = option; \\n    }\\n  }); \\n  \\n  // Update display items and total\\n  var subtotal = '100.00';\\n  var shippingPrice = selectedShippingOption.amount.value; \\n  var totalAmount = (Number(subtotal) + Number(shippingPrice)).toFixed(2);   \\n  var displayItems = [\\n    {\\n      label: 'Subtotal',\\n      amount: {currency: 'USD', value: subtotal}\\n    },\\n    {\\n      label: selectedShippingOption.label,\\n      amount: {currency: 'USD', value: shippingPrice}\\n    }\\n  ]; \\n  var total = {\\n    label: 'Total', \\n    amount: {currency: 'USD', value: totalAmount}\\n  }; \\n  \\n  // Update payment UI\\n  ev.updateWith({\\n    displayItems: displayItems, \\n    total: total, \\n    shippingOptions: availableShippingOptions\\n  }); \\n}); \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>\n\n## Styling the Payment Request button \nTo 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%. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var style = {\\n  theme: 'light', // default is 'dark'\\n  text: 'Check out' // default is 'Pay now'\\n}; \\npaymentRequest.showButton(style)\\n.then(...).catch(...); \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe 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. \n[block:html]\n{\n  \"html\": \"<div style=\\\"float:left\\\">\"\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/29bb0a9-buttons.png\",\n        \"buttons.png\",\n        262,\n        43,\n        \"#215aaa\"\n      ],\n      \"caption\": \"\"\n    }\n  ]\n}\n[/block]\n\n[block:html]\n{\n  \"html\": \"</div>\\n<div style=\\\"clear:both;\\\"></div>\"\n}\n[/block]\n## Using your own button to show the payment UI\nIf 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). \n\nWhen the promise resolves, send the token to your server and process the transaction using the Payment API (click [here](/v8976-Tools/docs/hosted-payment-fields#section-in-the-payment-api) 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.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"paymentRequest.show()\\n.then(function(ev) {\\n  // The shopper confirmed the purchase\\n  // Send ev.token to your server and process the transaction...\\n      \\n  // ... Report the transaction result to the browser\\n  ev.complete('success'); // or ev.complete('fail');\\n}) \\n.catch(function(err) {\\n  // The shopper closed the payment UI\\n  console.log(err); \\n}); \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n## Possible errors\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Code\",\n    \"h-1\": \"Description\",\n    \"0-0\": \"missing_required_field\",\n    \"0-1\": \"Required field {...} is missing\",\n    \"1-0\": \"invalid_value\",\n    \"1-1\": \"The value {...} for field {...} is invalid\"\n  },\n  \"cols\": 2,\n  \"rows\": 2\n}\n[/block]\n<a class=\"btn btn-primary\" href=\"#\" role=\"button\">Back to Top</a>","excerpt":"","slug":"payment-request-api","type":"basic","title":"Payment Request API (W3C)"}

Payment Request API (W3C)


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 will cover the following topics:

Try it now

Use a supported browser to try it below. Your card will not be charged.

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_

Back to Top

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
}

Back to Top

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 the data-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); 
}); 

Back to Top

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); 
});   

Back to Top

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']
      }
    }]
};

Back to Top

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(...);

Back to Top

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
    }); 
  }
}); 

Back to Top

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
  }); 
}); 

Back to Top

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