{"metadata":{"image":[],"title":"","description":""},"api":{"url":"","auth":"required","settings":"","results":{"codes":[]},"params":[]},"next":{"description":"","pages":[]},"title":"Payment Request Button","type":"basic","slug":"payment-request-button","excerpt":"The Payment Request Button solution (also known as a Wallet Button) provides a single integration for ApplePay and Google Pay.","body":"With our Payment Request Button solution, also known as a *Wallet Button*, you can provide a single integration where shoppers see either a Google Pay button, an Apple Pay button or both, depending on the device and the browser specifics. If neither option is available, nothing is shown.  \n\nThis guide covers the following topics:\n\n* [Supported browsers](#section-supported-browsers)\n* [Prerequisites](#section-prerequisites)\n* [Implementing the Payment Request Button](#section-implementing-the-payment-request-button)\n* [Error codes](#section-error-codes)\n\n# Supported browsers \n##Google Pay \n* Supports Google Chrome, Mozilla Firefox, Apple Safari, Microsoft Edge, Opera, and UCWeb UC Browser.\n* For supported countries, refer [here](https://support.google.com/pay/answer/9023773?hl=en).\n* For more information about Google Pay, refer [here](https://developers.google.com/pay/api/web/overview).\n\n## ApplePay\n* Browsers:\n  * Worldwide (except China):  iOS 10 and later, macOS 10.12 and later (Safari)\n  * China: iOS 11.2 and later (Not available in macOS)\n* For supported countries, refer [here](https://www.apple.com/ios/feature-availability/#apple-pay).\n* For more information about ApplePay support, refer [here](https://developer.apple.com/documentation/apple_pay_on_the_web).\n\n# Prerequisites\n\n1. Verify your domain with Apple Pay.  A requirement for both development and production.  Refer to [Verify your domain](https://developers.bluesnap.com/docs/apple-pay#section-step-1-verify-your-domain) for more details.\n\n2. In the BlueSnap Control Panel, ensure that the Google Pay and ApplePay payment methods are enabled.\n\n3.  Application must be served over HTTPS. A requirement for both development and production.\n\n4. You must have a BlueSnap account.  If you don't have an account yet, you can [sign up for one here](http://home.bluesnap.com/get-started/).\n\n5. By integrating Google Pay, you agree to Google’s terms and conditions. For more details, [refer here](https://payments.developers.google.com/terms/sellertos).\n\n# Implementing the Payment Request Button\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Insert the domain for either Sandbox or Production\",\n  \"body\": \"In all steps below, replace the `BLUESNAPDOMAINPATH` with the relevant domain for either\\nthe BlueSnap sandbox or production environment, as follows:\\n*  Sandbox: `https://sandbox.bluesnap.com`\\n*  Production: `https://ws.bluesnap.com`\\n\\nFor example, the Payment Request Button token request (in step 1) should be sent to:\\n* `https://sandbox.bluesnap.com/services/2/payment-fields-tokens` on Sandbox\\nOR\\n* `https://ws.bluesnap.com/services/2/payment-fields-tokens` on Production\"\n}\n[/block]\nFollow the steps below to implement Payment Request.\n\n1. [Obtain the Payment Request Button token for the session](#section-step-1-obtain-the-payment-request-button-token-for-the-session)\n\n2. [Add the BlueSnap JavaScript file to your checkout form](#section-step-2-add-the-bluesnap-javascript-file-to-your-checkout-form)\n\n3. [Add a div element to your page](#section-step-3-add-a-div-element-to-your-page)\n\n4. [Activate Payment Request Button Setup](#section-step-4-activate-the-payment-request-button-setup)\n\n5. [Process the payment using the token](#section-step-5-process-the-payment-using-the-token)\n\n## Step 1: Obtain the Payment Request Button token for the session\n        \nObtain the Payment Request Button token by sending a server-to-server POST request to:       \n`BLUESNAPDOMAINPATH/services/2/payment-fields-tokens`\n        \nThe response provides the token in the location header. For example:     \n`BLUESNAPDOMAINPATH/services/2/payment-fields-tokens/HOSTEDFIELDTOKENID`\n[block:callout]\n{\n  \"type\": \"success\",\n  \"body\": \"The Payment Request Button token expires after 60 minutes.\",\n  \"title\": \"Note\"\n}\n[/block]\n## Step 2: Add the BlueSnap JavaScript file to your checkout form\nIn your checkout form, call the BlueSnap Payment Request Button JavaScript file by adding the following script:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script type=\\\"text/javascript\\\" src=\\\"BLUESNAPDOMAINPATH/web-sdk/4/bluesnap.js\\\"></script> \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n## Step 3: Add a div element to your page\n\nAdd the following `div` element to your page.  BlueSnap uses this to create the Payment Request Buttons.\n\n`<div data-bluesnap=\"walletButton\"></div>`\n\n## Step 4: Activate the Payment Request Button setup\nTo activate the setup, you must create the sdk request object.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"SdkRequest = {\\n    token: 'TOKEN_STRING', // The token you created in Step 1.\\n    googlePay: true, // OPTIONAL default is true.\\n    applePay: false, // OPTIONAL default is true.\\n    paymentData: {\\n        currencyCode: 'USD', // The three-letter ISO 4217 currency code for the payment.\\n         countryCode: 'US', // The merchant’s two-letter ISO 3166 country code.\\n        total: {\\n            label: 'My Total',\\n            amount: '123.45',\\n        }                                },\\n        // Use black buttons on white or light backgrounds to provide contrast.\\n        // Use white buttons on dark or colorful backgrounds.\\n        theme: 'white', // OPTIONAL black or white default is 'black'\\n        emailRequired: true, // OPTIONAL default false\\n        phoneRequired: true, // OPTIONAL default false\\n        fullBilling: true, // OPTIONAL default false\\n        shippingRequired: true, // OPTIONAL default false\\n        shippingOptions: [ // OPTIONAL, MANDATORY if shippingRequired: true\\n          { // first item is the default selection\\n            identifier: \\\"FREE\\\",\\n            detail: \\\"A free of charge\\\",\\n            label: \\\"my label\\\",\\n            amount: \\\"12.23\\\"\\n          },\\n          {\\n            identifier: \\\"EXPRESS\\\",\\n            detail: \\\"A costly one\\\",\\n            label: \\\"my second label\\\",\\n            amount: \\\"45.1\\\"\\n          }\\n        ]\\n    },\\n    onEvent: { // this event handler will handle all the events arriving from the Payment Request Button\\n        paymentAuthorized: function (success, error) {\\n            // here you will create the transaction Server2Server call Auth / Capture\\n            // transaction result will decide which function to activate\\n            // according to the transaction result status we will activate either success() or error()\\n            if (transactionResultStatus === 'success') {\\n                success();\\n            } else {\\n                error('here you will write a msg to the shopper')\\n            }\\n            // Note: IT IS MANDATORY TO CALL ONE OF THE FUNCTIONS.                    \\n        },\\n        shippingOptionChange: function (shippingOptionsData, oldData, update) {\\n            // shippingOptionsData = {identifier}  \\n            // oldData = {currencyCode, countryCode, total, shippingOptions}                               \\n            // relevant only if shipping option is true\\n            // IT IS MANDATORY TO CALL update() IN ONE OF THE VARIATION BELOW           \\n            update({ total, shippingOptions, error }); // or update({}); for no change\\n        },\\n        shippingAddressChange: function (shippingAddressData, oldData, update) {\\n            // shippingAddressData = {administrativeArea, countryCode, locality, postalCode}   \\n            // oldData = {currencyCode, countryCode, total, shippingOptions}                        \\n            // relevant only if shippingRequired is true\\n            // IT IS MANDATORY TO CALL update() IN ONE OF THE VARIATION BELOW           \\n            update({ total, shippingOptions, error }); // or update({}); for no change\\n        },\\n        error: function (event) {\\n            // handle error event\\n            /* for example when code = 40 (Can't use requested Wallet/s, no payment option is available)\\n            event = {\\n                status: \\\"No payment method available\\\",\\n                code: \\\"40\\\",\\n                info: {\\n                    errors: [                                 \\n                            \\\"Can't use requested Wallet/s, no payment option is available.\\\"                                  \\n                    ]                        \\n                }                    \\n            */\\n        },\\n        warning: function (event) {\\n            // handle warning event\\n\\n        },\\n\\n    },\\n\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n*  For more information, refer to:\n  * [`paymentData` object](#section--paymentdata-object)\n  * [`total` object](#section--total-object)\n  *  [`shippingOption` object](#section--shippingoption-object)\n\nAfter you create the object, activate the setup function using the sdk request object you created.\n\n`bluesnap.walletButtonSetup(sdkRequest);`\n    \nThe relevant buttons will now be displayed as applicable inside the element container.\n\n## Step 5: Process the payment using the token\n\nWhen the shopper confirms the purchase (activating the payment authorized event from the `sdkRequest` event handler), you must send the token to your server and process the transaction using the Payment API [Hosted Payment Fields](https://developers.bluesnap.com/v8976-Tools/docs/hosted-payment-fields#section-in-the-payment-api). \nAfter you receive the response, you must communicate the result to the browser using either `success` or `error` functions.  This prompts the browser to close the payment UI or display an error message.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// taken from the sdkRequest event handler\\n    \\n    paymentAuthorized: function (success, error) {\\n                 // here you will create the transaction Server2Server call Auth/Capture\\n                 // transaction result will decide which function to activate\\n                 // according to the transaction result status we will activate either success() or error()\\n                 if (transactionResultStatus === 'success') {\\n                     success();\\n                 } else {\\n                     error('here you will write a msg to the shopper')\\n                 }               \\n                 // Please Note: IT IS MANDATORY TO CALL ONE OF THE FUNCTIONS.                     \\n    },\",\n      \"language\": \"javascript\",\n      \"name\": null\n    }\n  ]\n}\n[/block]\nAfter the event triggers, you can then process payments by including the Payment Request Button token in your API requests. This must be done from your server and requires using your API Credentials.\n\nFor more information, refer to [Completing Tokenized Payments](https://developers.bluesnap.com/v8976-Basics/docs/completing-tokenized-payments).\n\n## Object details\n\n### `sdkRequest` object\n\n| Property | Type | Required | Description |\n| --- | --- | --- | --- |\n| `token` | string | **Required** |  [Obtain the Payment Request Button token for the session](#section-step-1-obtain-the-payment-request-button-token-for-the-session) |\n| `googlePay` | boolean | optional | Indicate if you want to activate the Google Pay button. Default = `true`. |\n| `applePay` | boolean | optional | Indicate if you want to activate the ApplePay button. Default = `true`. |\n| `paymentData` | [PaymentData](#section--paymentdata-object) | **Required** |  &nbsp; |\n| `onEvent` | [OnEvent](#section--onevent-object) | **Required** | &nbsp; |\n\n### `paymentData` object\nThe following properties within the `paymentData` object let you tell the browser exactly what it should display in the wallet UI and define what details it should collect from the shopper (such as email and phone).\n\n| Property | Type | Required | Description |\n| --- | --- | --- | --- |\n| `currencyCode` | string | **Required** | ISO 4217 alphabetic currency code. |\n| `countryCode` | string | **Required** | ISO 3166-1 alpha-2 country code where the transaction is processed. This is required for merchants based in European Economic Area (EEA) countries. |\n| `total` | [Total](#section--total-object) | **Required** | An object defining the amount of the transaction and how it should be displayed in the wallet). |\n| `theme` | string | optional | `white` or 'black`. Default = `black`. |\n| `shippingRequired` | boolean | optional | Set to `true` to request shipping. Default = `false`. |\n| `shippingOptions` | [ShippingOption](#section--shippingoption-object) | **Required** if `shippingRequired` = `true` | List of objects containing the data of your shipping options that will be displayed in the wallet. Note: The first item in the list is selected by default. |\n| `emailRequired` | boolean | optional | Set to `true` to request an email address. |\n| `phoneRequired` | boolean | optional | Set to `true` to request a phone number. |\n| `fullBilling` | boolean | optional | Set to `true` to request full billing from the shopper. |\n\nFor a minimal payment data use:         \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"let paymentData = {\\n  currencyCode: 'USD',\\n  countryCode: 'US',\\n  total: {\\n    label: 'My final total',\\n    amount: '123.45',\\n  }\\n};\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n### `total` object\n| Property | Type | Required | Description |\n| --- | --- | --- | --- |\n| `amount` | string | **Required** | Total monetary value of the transaction with an optional decimal precision of two decimal places. Note: The format of the string should follow the regex /^[0-9]+(.[0-9][0-9])?$/ |\n| `label` | string | **Required** | Custom label for the total price within the display items. |\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"let total = {\\n  label: 'My final total',\\n  amount: '123.45'\\n};\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n### `shippingOption` object\nIf you sell physical goods that need to be shipped, tell the browser to collect the shopper's shipping address in the payment UI by including `shippingRequired: true` within `PaymentData` object when you initialize `sdkRequest`.  If the shipping options depend on the shopper's address, you may also want to provide shippingOptions at this time.\n\n| Property | Type | Required | Description |\n| --- | --- | --- | --- |\n| `identifier` | string | **Required** | An identifier that is used later if `shippingOptionChanged` callback was provided. |\n| `amount` | string | **Required** | An amount to display regarding the shipping option cost. |\n| `label` | string | **Required** | The label to be displayed as the option. |\n| `detail` | string | **Required** | Detail to display. |\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"let shippingOptions = [\\n  {\\n    identifier: 'shipping-001',\\n    detail: 'A free of charge shipping',\\n    label: '10 business days',\\n    amount: '0.00',\\n  },\\n  {\\n    identifier: 'shipping-002',\\n    detail: 'An express shipping',\\n    label: '3 business days',\\n    amount: '10.00',\\n  },\\n];\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n### `onEvent` object\n| Property | Type | Required | Description |\n| --- | --- | --- | --- |\n| `paymentAuthorized` | `Function(success, error)` | **Required** | |\n| `shippingOptionChange` | `Function(shippingOptionsData, oldData, update)` | optional |  [Handle shipping options changes](#section-step-2-handle-shipping-options-changes) |\n| `shippingAddressChange` | `Function(shippingAddressData, oldData, update)` | optional |  [Handle shipping address changes](#section-step-1-handle-shipping-address-changes) |\n | `error` | Function(event) | **Required** | &nbsp; |\n | `warning` | Function(event) | optional | &nbsp; |\n\n### `paymentAuthorized` property\nHere you create the transaction Server2Server call Auth/Capture.\nThe transaction result determines which function to activate.\nBased on the transaction result status, activate either `success()` or `error()`.              \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \".\\n.\\n.\\nif (transactionResultStatus === 'success') {\\n  success();\\n} else {\\n  error('here you will write a msg to the shopper')\\n}\\n.\\n.\\n.               \\nNote: IT IS MANDATORY TO CALL ONE OF THE FUNCTIONS.\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n### `error` property\nHandle error event, for example when code = 40.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"event = {\\n  status: 'No payment method available',\\n  code: '40',\\n  info: {\\n    errors: [\\n      \\\"Can't use requested Wallet/s, no payment option is available.\\\"\\n    ]\\n  }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n### `warning` property\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"event = {\\n  status: 'Invalid Data',\\n  code: '15',\\n  info: {\\n    warnings: [\\n      'shippingRequired was set to true but shippingOptions was not provided'\\n    ]\\n  }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n## Collecting shipping information\n### Step 1: Handle shipping address changes\n\nListen to the `shippingAddressChange` event [`sdkRequest.onEvent`](#section--onevent-object) 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. \nTo update the payment UI, call `update({total, shippingOptions, error})` with total, 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 `update({})` for no change\n\n | Property | Type |\n | --- | --- |\n | `shippingAddressData` | [`shippingAddressData` object](#section--shippingaddressdata-object)  |\n | `oldData` | [`oldData` object](#section--olddata-object)|\n | `update` |  [`update` function](#section--update-function) |\n\n### `shippingAddressData` Object\n | Property | Type | Description |\n | --- | --- | --- |\n | `administrativeArea` | string | country sub division, such as state or province |\n | `countryCode` | string | ISO 3166-1 alpha-2 country code where the transaction is processed. This is required for merchants based in European Economic Area (EEA) countries. |\n | `locality` | string | city, town, neighborhood, suburb |\n | `postalCode` | string | zip code |\n\n### `oldData` object\n | Property | Type | Description |\n | --- | --- | --- |\n | `currencyCode` | string | ISO 4217 alphabetic currency code. |\n | `countryCode` | string | ISO 3166-1 alpha-2 country code where the transaction is processed. This is required for merchants based in European Economic Area (EEA) countries. |\n | `total` | [`Total` object](#section--total-object) | &nbsp; |\n | `shippingOptions` | [`shippingOption` object](#section--shippingoption-object) | List of objects containing the data of your shipping options that will be displayed in the wallet. Note: The first item in the list is selected by default. |\n\n### `update` function\n| Property | Type |\n| --- | ---  |\n| `total` | [`Total` object](#section--total-object) |\n| `shippingOptions` | [`shippingOption` object](#section--shippingoption-object) |\n| `error` | [`updateError` object](#section--updateerror-object)  |\n\n### `updateError` object\n| Property | Type |\n| --- | --- | \n| `reason` | type of string can only get either 'SHIPPING_ADDRESS_INVALID' or 'SHIPPING_ADDRESS_UNSERVICEABLE' |\n| `message` | string |\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"sdkRequest: {\\n  //...\\n  onEvent: {\\n    shippingAddressChange: function (\\n      shippingAddressData,\\n      oldData,\\n      update\\n    ) {\\n      if (shippingAddressData.countryCode !== 'US') {\\n        // Shipping address is invalid since merchant doesn't ship outside the US\\n        // Update payment UI with an error\\n        // IT IS MANDATORY TO CALL THE update() BELOW\\n        update({\\n          error: {\\n            message: 'Can only ship to the US',\\n            reason: 'SHIPPING_ADDRESS_INVALID '\\n          }\\n        });\\n      } else {\\n        // Shipping address is valid\\n        // Fetch shipping options...\\n        //... return shipping options\\n        // For example:\\n        let shippingOptions = [\\n          {\\n            // first item is the default selection\\n            identifier: 'FREE',\\n            detail: 'A free of charge',\\n            label: 'my label',\\n            amount: '12.23'\\n          },\\n          {\\n            identifier: 'EXPRESS',\\n            detail: 'A costly one',\\n            label: 'my second label',\\n            amount: '45.1'\\n          }\\n        ];\\n\\n        // Update payment UI\\n        update({\\n          total: {\\n            label: 'My final total',\\n            amount: '123.45'\\n          },\\n          shippingOptions: shippingOptions\\n        });\\n      }\\n    }\\n  }\\n  //...\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n### Step 2: Handle shipping options changes\n\nListen to the shippingOptionChange event to know when the shopper selects a shipping option, \nproviding you the opportunity to mark the shipping option as selected and to update the total. \nSimilar to the previous step, call `update({total, shippingOptions, error})` with the updated details \n(or call `update({})` if no changes to the payment UI are required).\n\n| Property | Type |\n| --- | --- | \n| `shippingOptionsData` | [`shippingOptionsData` object](#section--shippingoptionsdata-object) |  \n| `oldData` | [`oldData` object](#section--olddata-object) | \n| `update` | [`update` function](#section--update-function) | \n\n#### `shippingOptionsData` object\n| Property | Type |\n| --- | --- |\n| `identifier` | string | \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"sdkRequest: {\\n  //...\\n  onEvent: {\\n    shippingOptionChange: function (\\n      shippingOptionsData,\\n      oldData,\\n      update\\n    ) {\\n      // Get the ID of the selected shipping option\\n      let selectedId = shippingOptionsData.identifier;\\n\\n      // extract selected option\\n      let selectedShippingOption;\\n      oldData.shippingOptions.forEach(function (option) {\\n        if (option.identifier === selectedId) {\\n          selectedShippingOption = option;\\n        }\\n      });\\n\\n      // Update display items and total\\n      let subtotal = '100.00'; // total without shipping\\n      let shippingPrice = selectedShippingOption.amount;\\n      let totalAmount = (\\n        Number(subtotal) + Number(shippingPrice)\\n      ).toFixed(2);\\n      let total = {\\n        label: 'My final total',\\n        amount: totalAmount.toString()\\n      };\\n\\n      // Update payment UI\\n\\n      // IT IS MANDATORY TO CALL THE update() IN ONE OF THE VARIATION BELOW\\n      update({\\n        total: total\\n      });\\n    }\\n  }\\n  //...\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n# Error codes\n| Code | Description |\n| --- | --- |\n| 10 | Invalid Data |\n| 20 | Inner Error |\n| 40 | Can't use the requested wallet(s), no payment option is available |\n| 14040 | Token is expired |\n| 14041 | Could not find the token |\n| Other codes are the standard HTTP codes | Server Error |","updates":[],"order":0,"isReference":false,"hidden":false,"sync_unique":"","link_url":"","link_external":false,"_id":"5f4d276c4ff932005f3e3b82","createdAt":"2020-04-03T19:01:10.269Z","user":"5beb1b96bc2003003ecd645e","category":{"sync":{"isSync":false,"url":""},"pages":[],"title":"Payment Request Button","slug":"wallet-button","order":10,"from_sync":false,"reference":false,"_id":"5f4d276b4ff932005f3e3b41","createdAt":"2020-04-03T19:00:57.681Z","version":"5f4d276c4ff932005f3e3b86","project":"57336fd5a6a9c40e00e13a0b","__v":0},"version":{"version":"8976-Tools","version_clean":"8976.0.0-Tools","codename":"3.35 Release","is_stable":false,"is_beta":false,"is_hidden":false,"is_deprecated":false,"categories":["5f4d276b4ff932005f3e3b33","5f4d276b4ff932005f3e3b34","5f4d276b4ff932005f3e3b35","5f4d276b4ff932005f3e3b36","5f4d276b4ff932005f3e3b37","5f4d276b4ff932005f3e3b38","5f4d276b4ff932005f3e3b39","5f4d276b4ff932005f3e3b3a","5f4d276b4ff932005f3e3b3b","5f4d276b4ff932005f3e3b3c","5f4d276b4ff932005f3e3b3d","5f4d276b4ff932005f3e3b3e","5b34c737e0dca2000311de6a","5f4d276b4ff932005f3e3b3f","5f4d276b4ff932005f3e3b40","5f4d276b4ff932005f3e3b41","5f4d276b4ff932005f3e3b42","5f4d2af1ca14ec003918818c","5f4e66c5c9098e01d05608cf"],"_id":"5f4d276c4ff932005f3e3b86","project":"57336fd5a6a9c40e00e13a0b","__v":2,"forked_from":"5f076ef5f118570458067d0f","createdAt":"2018-04-23T15:17:35.680Z","releaseDate":"2018-04-23T15:17:35.680Z"},"project":"57336fd5a6a9c40e00e13a0b","__v":0,"parentDoc":null}

Payment Request Button

The Payment Request Button solution (also known as a Wallet Button) provides a single integration for ApplePay and Google Pay.

With our Payment Request Button solution, also known as a Wallet Button, you can provide a single integration where shoppers see either a Google Pay button, an Apple Pay button or both, depending on the device and the browser specifics. If neither option is available, nothing is shown.

This guide covers the following topics:

Supported browsers

Google Pay

  • Supports Google Chrome, Mozilla Firefox, Apple Safari, Microsoft Edge, Opera, and UCWeb UC Browser.
  • For supported countries, refer here.
  • For more information about Google Pay, refer here.

ApplePay

  • Browsers:
    • Worldwide (except China): iOS 10 and later, macOS 10.12 and later (Safari)
    • China: iOS 11.2 and later (Not available in macOS)
  • For supported countries, refer here.
  • For more information about ApplePay support, refer here.

Prerequisites

  1. Verify your domain with Apple Pay. A requirement for both development and production. Refer to Verify your domain for more details.

  2. In the BlueSnap Control Panel, ensure that the Google Pay and ApplePay payment methods are enabled.

  3. Application must be served over HTTPS. A requirement for both development and production.

  4. You must have a BlueSnap account. If you don't have an account yet, you can sign up for one here.

  5. By integrating Google Pay, you agree to Google’s terms and conditions. For more details, refer here.

Implementing the Payment Request Button

Insert the domain for either Sandbox or Production

In all steps below, replace the BLUESNAPDOMAINPATH with the relevant domain for either
the BlueSnap sandbox or production environment, as follows:

  • Sandbox: https://sandbox.bluesnap.com
  • Production: https://ws.bluesnap.com

For example, the Payment Request Button token request (in step 1) should be sent to:

  • https://sandbox.bluesnap.com/services/2/payment-fields-tokens on Sandbox
    OR
  • https://ws.bluesnap.com/services/2/payment-fields-tokens on Production

Follow the steps below to implement Payment Request.

  1. Obtain the Payment Request Button token for the session

  2. Add the BlueSnap JavaScript file to your checkout form

  3. Add a div element to your page

  4. Activate Payment Request Button Setup

  5. Process the payment using the token

Step 1: Obtain the Payment Request Button token for the session

Obtain the Payment Request Button token by sending a server-to-server POST request to:
BLUESNAPDOMAINPATH/services/2/payment-fields-tokens

The response provides the token in the location header. For example:
BLUESNAPDOMAINPATH/services/2/payment-fields-tokens/HOSTEDFIELDTOKENID

Note

The Payment Request Button token expires after 60 minutes.

Step 2: Add the BlueSnap JavaScript file to your checkout form

In your checkout form, call the BlueSnap Payment Request Button JavaScript file by adding the following script:

<script type="text/javascript" src="BLUESNAPDOMAINPATH/web-sdk/4/bluesnap.js"></script> 

Step 3: Add a div element to your page

Add the following div element to your page. BlueSnap uses this to create the Payment Request Buttons.

<div data-bluesnap="walletButton"></div>

Step 4: Activate the Payment Request Button setup

To activate the setup, you must create the sdk request object.

SdkRequest = {
    token: 'TOKEN_STRING', // The token you created in Step 1.
    googlePay: true, // OPTIONAL default is true.
    applePay: false, // OPTIONAL default is true.
    paymentData: {
        currencyCode: 'USD', // The three-letter ISO 4217 currency code for the payment.
         countryCode: 'US', // The merchant’s two-letter ISO 3166 country code.
        total: {
            label: 'My Total',
            amount: '123.45',
        }                                },
        // Use black buttons on white or light backgrounds to provide contrast.
        // Use white buttons on dark or colorful backgrounds.
        theme: 'white', // OPTIONAL black or white default is 'black'
        emailRequired: true, // OPTIONAL default false
        phoneRequired: true, // OPTIONAL default false
        fullBilling: true, // OPTIONAL default false
        shippingRequired: true, // OPTIONAL default false
        shippingOptions: [ // OPTIONAL, MANDATORY if shippingRequired: true
          { // first item is the default selection
            identifier: "FREE",
            detail: "A free of charge",
            label: "my label",
            amount: "12.23"
          },
          {
            identifier: "EXPRESS",
            detail: "A costly one",
            label: "my second label",
            amount: "45.1"
          }
        ]
    },
    onEvent: { // this event handler will handle all the events arriving from the Payment Request Button
        paymentAuthorized: function (success, error) {
            // here you will create the transaction Server2Server call Auth / Capture
            // transaction result will decide which function to activate
            // according to the transaction result status we will activate either success() or error()
            if (transactionResultStatus === 'success') {
                success();
            } else {
                error('here you will write a msg to the shopper')
            }
            // Note: IT IS MANDATORY TO CALL ONE OF THE FUNCTIONS.                    
        },
        shippingOptionChange: function (shippingOptionsData, oldData, update) {
            // shippingOptionsData = {identifier}  
            // oldData = {currencyCode, countryCode, total, shippingOptions}                               
            // relevant only if shipping option is true
            // IT IS MANDATORY TO CALL update() IN ONE OF THE VARIATION BELOW           
            update({ total, shippingOptions, error }); // or update({}); for no change
        },
        shippingAddressChange: function (shippingAddressData, oldData, update) {
            // shippingAddressData = {administrativeArea, countryCode, locality, postalCode}   
            // oldData = {currencyCode, countryCode, total, shippingOptions}                        
            // relevant only if shippingRequired is true
            // IT IS MANDATORY TO CALL update() IN ONE OF THE VARIATION BELOW           
            update({ total, shippingOptions, error }); // or update({}); for no change
        },
        error: function (event) {
            // handle error event
            /* for example when code = 40 (Can't use requested Wallet/s, no payment option is available)
            event = {
                status: "No payment method available",
                code: "40",
                info: {
                    errors: [                                 
                            "Can't use requested Wallet/s, no payment option is available."                                  
                    ]                        
                }                    
            */
        },
        warning: function (event) {
            // handle warning event

        },

    },

}

After you create the object, activate the setup function using the sdk request object you created.

bluesnap.walletButtonSetup(sdkRequest);

The relevant buttons will now be displayed as applicable inside the element container.

Step 5: Process the payment using the token

When the shopper confirms the purchase (activating the payment authorized event from the sdkRequest event handler), you must send the token to your server and process the transaction using the Payment API Hosted Payment Fields.
After you receive the response, you must communicate the result to the browser using either success or error functions. This prompts the browser to close the payment UI or display an error message.

// taken from the sdkRequest event handler
    
    paymentAuthorized: function (success, error) {
                 // here you will create the transaction Server2Server call Auth/Capture
                 // transaction result will decide which function to activate
                 // according to the transaction result status we will activate either success() or error()
                 if (transactionResultStatus === 'success') {
                     success();
                 } else {
                     error('here you will write a msg to the shopper')
                 }               
                 // Please Note: IT IS MANDATORY TO CALL ONE OF THE FUNCTIONS.                     
    },

After the event triggers, you can then process payments by including the Payment Request Button 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.

Object details

sdkRequest object

Property Type Required Description
token string Required Obtain the Payment Request Button token for the session
googlePay boolean optional Indicate if you want to activate the Google Pay button. Default = true.
applePay boolean optional Indicate if you want to activate the ApplePay button. Default = true.
paymentData PaymentData Required  
onEvent OnEvent Required  

paymentData object

The following properties within the paymentData object let you tell the browser exactly what it should display in the wallet UI and define what details it should collect from the shopper (such as email and phone).

Property Type Required Description
currencyCode string Required ISO 4217 alphabetic currency code.
countryCode string Required ISO 3166-1 alpha-2 country code where the transaction is processed. This is required for merchants based in European Economic Area (EEA) countries.
total Total Required An object defining the amount of the transaction and how it should be displayed in the wallet).
theme string optional white or 'black. Default =black`.
shippingRequired boolean optional Set to true to request shipping. Default = false.
shippingOptions ShippingOption Required if shippingRequired = true List of objects containing the data of your shipping options that will be displayed in the wallet. Note: The first item in the list is selected by default.
emailRequired boolean optional Set to true to request an email address.
phoneRequired boolean optional Set to true to request a phone number.
fullBilling boolean optional Set to true to request full billing from the shopper.

For a minimal payment data use:

let paymentData = {
  currencyCode: 'USD',
  countryCode: 'US',
  total: {
    label: 'My final total',
    amount: '123.45',
  }
};

total object

Property Type Required Description
amount string Required Total monetary value of the transaction with an optional decimal precision of two decimal places. Note: The format of the string should follow the regex /^[0-9]+(.[0-9][0-9])?$/
label string Required Custom label for the total price within the display items.
let total = {
  label: 'My final total',
  amount: '123.45'
};

shippingOption object

If you sell physical goods that need to be shipped, tell the browser to collect the shopper's shipping address in the payment UI by including shippingRequired: true within PaymentData object when you initialize sdkRequest. If the shipping options depend on the shopper's address, you may also want to provide shippingOptions at this time.

Property Type Required Description
identifier string Required An identifier that is used later if shippingOptionChanged callback was provided.
amount string Required An amount to display regarding the shipping option cost.
label string Required The label to be displayed as the option.
detail string Required Detail to display.
let shippingOptions = [
  {
    identifier: 'shipping-001',
    detail: 'A free of charge shipping',
    label: '10 business days',
    amount: '0.00',
  },
  {
    identifier: 'shipping-002',
    detail: 'An express shipping',
    label: '3 business days',
    amount: '10.00',
  },
];

onEvent object

Property Type Required Description
paymentAuthorized Function(success, error) Required
shippingOptionChange Function(shippingOptionsData, oldData, update) optional Handle shipping options changes
shippingAddressChange Function(shippingAddressData, oldData, update) optional Handle shipping address changes
error Function(event) Required  
warning Function(event) optional  

paymentAuthorized property

Here you create the transaction Server2Server call Auth/Capture.
The transaction result determines which function to activate.
Based on the transaction result status, activate either success() or error().

.
.
.
if (transactionResultStatus === 'success') {
  success();
} else {
  error('here you will write a msg to the shopper')
}
.
.
.               
Note: IT IS MANDATORY TO CALL ONE OF THE FUNCTIONS.

error property

Handle error event, for example when code = 40.

event = {
  status: 'No payment method available',
  code: '40',
  info: {
    errors: [
      "Can't use requested Wallet/s, no payment option is available."
    ]
  }
}

warning property

event = {
  status: 'Invalid Data',
  code: '15',
  info: {
    warnings: [
      'shippingRequired was set to true but shippingOptions was not provided'
    ]
  }
}

Collecting shipping information

Step 1: Handle shipping address changes

Listen to the shippingAddressChange event sdkRequest.onEvent 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 update({total, shippingOptions, error}) with total, 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 update({}) for no change

Property Type
shippingAddressData shippingAddressData object
oldData oldData object
update update function

shippingAddressData Object

Property Type Description
administrativeArea string country sub division, such as state or province
countryCode string ISO 3166-1 alpha-2 country code where the transaction is processed. This is required for merchants based in European Economic Area (EEA) countries.
locality string city, town, neighborhood, suburb
postalCode string zip code

oldData object

Property Type Description
currencyCode string ISO 4217 alphabetic currency code.
countryCode string ISO 3166-1 alpha-2 country code where the transaction is processed. This is required for merchants based in European Economic Area (EEA) countries.
total Total object  
shippingOptions shippingOption object List of objects containing the data of your shipping options that will be displayed in the wallet. Note: The first item in the list is selected by default.

update function

Property Type
total Total object
shippingOptions shippingOption object
error updateError object

updateError object

Property Type
reason type of string can only get either 'SHIPPING_ADDRESS_INVALID' or 'SHIPPING_ADDRESS_UNSERVICEABLE'
message string
sdkRequest: {
  //...
  onEvent: {
    shippingAddressChange: function (
      shippingAddressData,
      oldData,
      update
    ) {
      if (shippingAddressData.countryCode !== 'US') {
        // Shipping address is invalid since merchant doesn't ship outside the US
        // Update payment UI with an error
        // IT IS MANDATORY TO CALL THE update() BELOW
        update({
          error: {
            message: 'Can only ship to the US',
            reason: 'SHIPPING_ADDRESS_INVALID '
          }
        });
      } else {
        // Shipping address is valid
        // Fetch shipping options...
        //... return shipping options
        // For example:
        let shippingOptions = [
          {
            // first item is the default selection
            identifier: 'FREE',
            detail: 'A free of charge',
            label: 'my label',
            amount: '12.23'
          },
          {
            identifier: 'EXPRESS',
            detail: 'A costly one',
            label: 'my second label',
            amount: '45.1'
          }
        ];

        // Update payment UI
        update({
          total: {
            label: 'My final total',
            amount: '123.45'
          },
          shippingOptions: shippingOptions
        });
      }
    }
  }
  //...
}

Step 2: 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.
Similar to the previous step, call update({total, shippingOptions, error}) with the updated details
(or call update({}) if no changes to the payment UI are required).

Property Type
shippingOptionsData shippingOptionsData object
oldData oldData object
update update function

shippingOptionsData object

Property Type
identifier string
sdkRequest: {
  //...
  onEvent: {
    shippingOptionChange: function (
      shippingOptionsData,
      oldData,
      update
    ) {
      // Get the ID of the selected shipping option
      let selectedId = shippingOptionsData.identifier;

      // extract selected option
      let selectedShippingOption;
      oldData.shippingOptions.forEach(function (option) {
        if (option.identifier === selectedId) {
          selectedShippingOption = option;
        }
      });

      // Update display items and total
      let subtotal = '100.00'; // total without shipping
      let shippingPrice = selectedShippingOption.amount;
      let totalAmount = (
        Number(subtotal) + Number(shippingPrice)
      ).toFixed(2);
      let total = {
        label: 'My final total',
        amount: totalAmount.toString()
      };

      // Update payment UI

      // IT IS MANDATORY TO CALL THE update() IN ONE OF THE VARIATION BELOW
      update({
        total: total
      });
    }
  }
  //...
}

Error codes

Code Description
10 Invalid Data
20 Inner Error
40 Can't use the requested wallet(s), no payment option is available
14040 Token is expired
14041 Could not find the token
Other codes are the standard HTTP codes Server Error