Bixby Developer Center

Guides

Supporting Payments

To allow users to pay for purchases, Bixby provides native integration of Samsung Payment Services (SPS). Bixby's implementation supports the following payment gateways:

  • Adyen
  • Authorize.Net
  • BlueSnap
  • Braintree Blue
  • Braintree Orange
  • Merchant e-Solutions
  • Stripe
  • WePay

If your region is not currently supported by SPS, or you need to communicate with a different payment provider, you can use HTTP Delivery.

Note

Support for Samsung Payment Services is currently limited to specific developers. If you are interested in integrating Samsung Payment in your capsule, reach out to the Samsung Developer Relations team for more information.

HTTP Delivery

If you're using another payment provider, you can use http-delivery to have SPS communicate directly with their payment API.

Before You Start

If you choose this option, you'll need to have the following documentation on your compliance with the PCI Data Security Standard:

  • An Attestation of Compliance (AOC), which can be obtained from an appropriate PCI Self-Assessment Questionnaire
  • A current Attestation of Scan Compliance for security vulnerabilities from a PCI Approved Scanning Vendor (ASV)
  • Technical integration documentation for your service's API, including its production URL

After approval, Samsung Developer Relations will contact you and request this documentation.

Local HTTP Endpoints

Using http-delivery, you'll need to include keys that define the details of the SPS payment, including:

  • merchant ID
  • merchant URL
  • supported cards
  • whether CVV verification is required
  • payment details such as amount, currency, and itemized details

Here is an example of how the payment-methods block could look with SPS information:

action-endpoints {
action-endpoint (PaymentAction) {
local-endpoint ("PaymentAction.js")
accepted-inputs (payInfo, taxInfo, shipInfo, $vivContext, $sps)
payment-methods {
sps {
merchant-name (transfer-money-to-account)
http-delivery {
url {
template (https://transfer-money-to-account.com/purchase/post)
}
// optional, but required if testing in Simulator
test-api-hostname (https://transfer-money-to-account.com/)
supported-card (VISA)
supported-card (MASTER)
cvv-verification (false)
}
payment {
amount (payInfo.amount)
currency (payInfo.currency)
items (payInfo.items) {
where-each (item) {
item {
name ("#{value(item.name)}")
amount (item.amount)
count (item.count)
}
}
}
tax {
amount (taxInfo.amount)
}
shipping {
amount (shippingInfo.amount)
}
}
}
}
}
}
Note

The url key is optional. If it is not specified, you need to add it to the options in your JavaScript: options.url = "https://transfer-money-to-account".

The JavaScript implementation in PaymentAction.js could look like this:

var http = require('http');

module.exports.function = function paymentAction(payInfo, taxInfo, shipInfo, $vivContext, $sps) {
var options = {};
options.headers = {
"Content-Type" : "application/json",
"User" : "blah"
};
var body = {
product_id: 916598,
"card_number": "{{credit_card_number}}",
"card_cvv": "{{credit_card_verification_value}}",
"card_expire_month": "{{credit_card_month}}",
"card_expire_year": "{{credit_card_year}}"
};
options.body = JSON.stringify(body);
var response = http.spsProxyPost(options);
return response;
}

Using http.spsProxyPost instead of http.postUrl lets you embed variables and functions in the HTTP body, such as the credit card information in the example above.

Remote HTTP Endpoints

With remote endpoints, you provide the payments details as you do with local endpoints. However, you also provide headers and body details using variables and functions in the remote-endpoint block of your endpoints.bxb file:

...
action-endpoints {
action-endpoint (paymentAction) {
payment-methods {
sps {
merchant-name (transfer-money-to-account)
http-delivery {
url {
template (https://transfer-money-to-account.com/purchase/post)
}
spreedly-receiver-type (test)
// optional, but required if testing in Simulator
test-api-hostname (https://transfer-money-to-account.com/)
supported-card (VISA)
supported-card (MASTER)
cvv-verification (true)
}
payment {
amount (payInfo.amount)
currency (payInfo.currency)
// Both 'items' and 'item' are optional, but at least one needs to be present.
// It is possible to have multiple 'items' and 'item's and a combination of both.
items (payInfo.items) {
where-each (item) {
item {
name("#{value(item.name)}")
amount(item.amount)
count(item.count) // Optional. Should be specified when it applies.
}
}
}
}
}
}
remote-endpoint (https://transfer-money-to-account.com) {
headers {
header (some-merchant-api-header:some-header-value)
}
body {
template ("{ \"product_id\": \"916598\", \"card_number\": \"{{credit_card_number}}\", \"cvv\": \"{{credit_card_verification_value}}\" }\"")
}
method (POST)
}
}
}
...

For more information on SPS payments, read about related keys in the Reference Guide.

SPS Payment Variables and Functions

As part of the body or headers, you can include a number of credit card variables:

VariableDescription
credit_card_tokenThe payment method token
credit_card_numberThe full credit card number of the payment method
credit_card_verification_valueThe CVV of the credit card
credit_card_first_nameThe card holder's first name
credit_card_last_nameThe card holder's last name
credit_card_monthThe month of the card's expiration date (4)
credit_card_yearThe year of the card's expiration date (2015)
credit_card_expiration_dateThe card's full expiration date (2020-04-01)
credit_card_typeThe type of the card (see below)
credit_card_emailThe card holder's email address
credit_card_address1The card holder's billing address line 1
credit_card_address2The card holder's billing address line 2
credit_card_cityThe card holder's billing city
credit_card_stateThe card holder's billing state
credit_card_zipThe card holder's billing zip
credit_card_countryThe card holder's billing country
credit_card_phone_numberThe card holder's phone number

Valid values for credit_card_type are:

  • visa
  • master
  • american_express
  • discover
  • jcb
  • diners_club
  • dankort
  • maestro
  • carnet

Additionally, you can use the following functions in requests. These elements are inserted using the Mustache template syntax.

  • aes: Encrypt contents using the Advanced Encryption Standard (AES) symmetric encryption algorithm. Because the raw output of {{#aes}} is binary, it is often used within another encoding function, such as base64. The encryption mode can be CBC, CFB, OFB, or CTR.

    {{#aes}}key-length in bits,mode,initialization vector as bit array,encryption key{{/aes}}
    // example usage
    {{#base64}}{{#aes}}192,CBC,[23, 12, 1, 105, 1, 1, 11, 18, 9, 39, 191, 125, 20, 132, 2, 16],mysecretkeyXXXXXXXXXXXXX,{{ credit_card_number }}{{/aes}}{{/base64}}
  • base64: Encode contents as Base64.

  • binary_security_token: For receivers that require an x509 certificate (for example: Mastercard), the binary_security_token inserts the Base64 encoded certificate.

  • bytes_hex: Takes a hex string and turns it into raw bytes. This function is rarely useful by itself, but can be helpful when paired with functions such as aes.

      {{#bytes_hex}}hexadecimal string to decode{{/bytes_hex}}
  • card_type_mapping: Output a custom card brand.

      {{#card_type_mapping}}brand:output,brand:output{{/card_type_mapping}}
      // example usage
      {#card_type_mapping}}visa:Visa,master:MasterCard,american_express:American Express{{/card_type_mapping}}

    Any card types whose value is not mapped in the function body will have the default credit_card_type value used. For example, if Diners Club card type is not specified, the default diners_club would be output.

  • digest: Digests contents using the specified digest algorithm. The digest algorithm can be one of sha512 or sha256. Because the raw output is in binary form you will often use the digest function embedded within another encoding function, such as base64, to produce web-safe output.

    {{#base64}}{{#digest}}sha512,{{ credit_card_number }}{{/digest}}{{/base64}}
  • format_date: Parse a date value to a specific string format. The format specifier syntax is based on the posix date format.

    {{#format_date}}%m%y,{{credit_card_expiration_date}}{{/format_date}}
  • format_text: Parse text content to a specific format. Useful when right or left padding a value to a specific width, among other scenarios. The format specifier syntax is based on posix printf.

    {{#format_text}}%-20.20s,{{credit_card_number}}{{/format_text}}
  • gpg: For some SFTP endpoints (batch export), the receiver requires the uploaded file to be encrypted using GnuPG and their public key.

    {{#gpg}}full pem,recipient identity,file template to encrypt{{/gpg}}`

    The gpg function takes the public key in PEM form as the first argument, the target identity as the second (email address of the recipient), and the content to encrypt as the third. The third argument will be your entire templated export, which can include other receiver functions are variables.

  • hex_bytes: Takes a byte string and turns it into a hex string.

    {{#hex_bytes}}delimiter,byte string to encode{{/hex_bytes}}
  • hex_digest: Computes the HMAC of a given payload. The payload is returned as a hexadecimal string. The digest algorithm can be any of SHA1, SHA256, or SHA512.

    {{#hmac}}digest algorithm,secret key,payload whose digest is desired{{/hmac}}
  • last: Get the last characters of a value.

    {{#last}}num,contents{{/last}}
  • md5: Calculate the MD5 digest of the contents.

    {{#md5}}value to digest{{/md5}}
  • replace: Replaces every instance of a given pattern with a new value in the content. Neither the pattern nor replacement can themselves contain commas.

    {{#replace}}pattern,replacement,content{{/replace}}
  • rsa: Encrypts contents using RSA public key cryptography. The certificate value must be in PEM format. The currently available padding schemes include: pkcs1 or oaep. Because the raw output is in binary form you will often use the rsa function embedded within another encoding function, such as base64, to produce web-safe output.

    {{#rsa}}certificate-pem,padding-scheme,contents to encrypt{{/rsa}}
  • rsa_sign: Signs (and base64 encodes) contents using the private key configured for the receiver. Requires a receiver pre-configured with an encryption certificate. The digest algorithm can be sha512 or sha256.

    {{#rsa_sign}}digest-algorithm,contents to sign{{/rsa_sign}}
  • triple_des: Encrypt contents using the Triple DES (3DES) symmetric encryption algorithm. The encryption mode can be CBC, CFB, OFB, or CTR. Because the raw output is binary, it is often used within another encoding function, such as base64.

    {{#triple_des}}mode,initialization vector as byte array,encryption key,data{{/triple_des}}
    // example usage
    {{#hex_bytes}}-,{{#triple_des}}CBC,[15, 66, 13, 102, 1, 1, 11, 18],testKeyXXXXXXXXXXXXXXXXX,1234123412341234{{/triple_des}}{{/hex_bytes}}

    Note that 3DES encryption is not generally acceptable for use in a PCI-compliant context, as 3DES encryption can be broken in a trivial amount of time on normal desktop computers and cell phones. You should instead use alternative mechanisms, such as AES encryption, in most contexts.

  • truncate: Truncate a value to a given size.

    {{#truncate}}length,contents{{/truncate}}
  • utc_timestamp: Inserts an ISO 8601 formatted timestamp at the time of export.

    {{#utc_timestamp}}{{/utc_timestamp}}
  • xml_dsig: Generate the WS-Security XML digital signature for a given SOAP envelope. Requires a receiver pre-configured with an encryption certificate.

    {{#xml_dsig}}full XML body{{/xml_dsig}}

Passing a User's Non-Sensitive Card Information

You can add a special $paymentCard input to your accepted inputs if you need to access non-sensitive information about the card confirmed by the user.

Note

This parameter is only available in actions that specify sps as their payment-methods in your action-endpoints.

accepted-inputs (payInfo, taxInfo, shipInfo, $vivContext, $paymentCard)

Here is the information that you can access via the $paymentCard parameter:

  • last4: The last four digits of the credit card. Example: 9999
  • address1: The first line of the billing address. Example: 1445 Norwood Ave
  • address1: The second line of the billing address, if needed. This is typically used for apartment or unit numbers. Example Building 5
  • city: The city of the billing address. Example: Itasca
  • state: The state of the billing address. Example: IL
  • zip: The zip code of the billing address. Example: 60143
  • country: The country of the billing address. Example: US
  • phone: The phone number of the customer, if provided. Example: 18885551212

Here is an example of using $paymentCard to get the billing address information.

First, create an action model:

action (AccessPaymentCard) {
type(Commit)
collect {
input (dummyInput) {
type (viv.core.Integer)
}
}
output (viv.core.Text)
}

In your corresponding JavaScript file, access the $paymentCard.%information% parameter to return the billing address information.

//AccessPaymentCard.js
module.exports.function = function paymentAction (dummyInput, $vivContext, $paymentCard) {
if ($paymentCard) {
console.log("$paymentCard.last4: " + $paymentCard.last4)
console.log("$paymentCard.address1: " + $paymentCard.address1)
console.log("$paymentCard.address2: " + $paymentCard.address2)
console.log("$paymentCard.city: " + $paymentCard.city)
console.log("$paymentCard.state: " + $paymentCard.state)
console.log("$paymentCard.zip: " + $paymentCard.zip)
console.log("$paymentCard.country: " + $paymentCard.country)
console.log("$paymentCard.phone: " + $paymentCard.phone)
} else {
console.log("$paymentCard is null")
}
...

You would then need to configure your endpoints for this action like below, including making sure that you set up the proper accepted-inputs for your endpoint:

action-endpoint (AccessPaymentCard) {
accepted-inputs (dummyInput, $vivContext, $paymentCard)
local-endpoint ("AccessPaymentCard.js")
}

Testing Payment Services

A real payment will never work from the Device Simulator. Instead, you'll need to add testing specific information. This might require temporarily modifying your code to use test tokens or gateway APIs.

Testing HTTP Delivery

To test an HTTP Delivery method, add a test-api-hostname key to the http-delivery block, specifying a valid URL to use for testing purposes.

action-endpoints {
action-endpoint (PaymentAction) {
local-endpoint ("PaymentAction.js")
accepted-inputs (payInfo, taxInfo, shipInfo, $vivContext, $sps)
payment-methods {
sps {
merchant-name (transfer-money-to-account)
http-delivery {
test-api-hostname (https://transfer-money-to-account.com/)
supported-card (VISA)
supported-card (MASTER)
cvv-verification (false)
}
payment {
amount (payInfo.amount)
currency (payInfo.currency)
items (payInfo.items) {
where-each (item) {
item {
name ("#{value(item.name)}")
amount (item.amount)
count (item.count)
}
}
}
}
}
}
}
}

When test-api-hostname is specified:

  • The request will be made to the URL specified in test-api-hostname, even if another URL for payment is sepcified in a url block.
  • The delivered payment information will use test card data. (This data is pre-defined and not configurable.)
  • All other parts of payment processing, including evaluating SPS payment variables and functions, will proceed as they would in production.

If possible, you should use a test API that can receive mocked payment information and return valid responses. If that is not possible, you can specify a server with test-api-hostname that simply logs the entire request, so you can verify that requests are formatted correctly.