{"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 Merchant Portal, 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** | |\n| `onEvent` | [OnEvent](#section--onevent-object) | **Required** | |\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** | |\n | `warning` | Function(event) | optional | |\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) | |\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":"6197defc41c8040154bcbab2","createdAt":"2020-04-03T19:01:10.269Z","user":"5beb1b96bc2003003ecd645e","category":{"sync":{"isSync":false,"url":""},"pages":[],"title":"Payment Request Button","slug":"wallet-button","order":11,"from_sync":false,"reference":false,"_id":"6197defc41c8040154bcba6e","createdAt":"2020-04-03T19:00:57.681Z","version":"6197defc41c8040154bcbaea","project":"57336fd5a6a9c40e00e13a0b","__v":0},"version":{"version":"8976-Tools","version_clean":"8976.0.0-Tools","codename":"3.40 Release","is_stable":false,"is_beta":false,"is_hidden":false,"is_deprecated":false,"categories":["6197defc41c8040154bcba61","6197defc41c8040154bcba62","6197defc41c8040154bcba63","6197defc41c8040154bcba64","6197defc41c8040154bcba65","6197defc41c8040154bcba66","6197defc41c8040154bcba67","6197defc41c8040154bcba68","6197defc41c8040154bcba69","6197defc41c8040154bcba6a","6197defc41c8040154bcba6b","6197defc41c8040154bcba6c","5b34c737e0dca2000311de6a","60957f4cce403c0045a031ef","6197defc41c8040154bcba6d","6197defc41c8040154bcba6e","6197defc41c8040154bcba6f","6197defc41c8040154bcba70","6197defc41c8040154bcba71","6197defc41c8040154bcba72"],"_id":"6197defc41c8040154bcbaea","project":"57336fd5a6a9c40e00e13a0b","__v":0,"forked_from":"60957f4cce403c0045a03255","createdAt":"2018-04-23T15:17:35.680Z","releaseDate":"2018-04-23T15:17:35.680Z"},"project":"57336fd5a6a9c40e00e13a0b","__v":0,"parentDoc":null}
Payment Request Button
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
Verify your domain with Apple Pay. A requirement for both development and production. Refer to Verify your domain for more details.
In the BlueSnap Merchant Portal, ensure that the Google Pay and ApplePay payment methods are enabled.
Application must be served over HTTPS. A requirement for both development and production.
You must have a BlueSnap account. If you don't have an account yet, you can sign up for one here.
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
ORhttps://ws.bluesnap.com/services/2/payment-fields-tokens
on Production
Follow the steps below to implement Payment Request.
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.
<script type="text/javascript" src="BLUESNAPDOMAINPATH/web-sdk/4/bluesnap.js"></script>
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
},
},
}
- For more information, refer to:
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.
event = {
status: 'No payment method available',
code: '40',
info: {
errors: [
"Can't use requested Wallet/s, no payment option is available."
]
}
}
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
});
}
}
//...
}