Programming guide

API Specification for Web Checkout development can be downloaded from Download section.


API Integration

You need to integrate with three Web Checkout APIs, Create transaction, Get payment credentials, and Notify payment result. The Samsung team provides the Web Checkout API specification document separately. For details, refer to the API specification from that document.

No Method URL Description
1 POST /ops/v1/transactions Create transaction with details
2 GET /ops/v1/transactions/paymentCredentials/{referenceId} Retrieve payment credentials
3 POST /ops/v1/notifications Notify the transaction result
4 HEAD /ops/v1/internal/health Checking bidirectional communication between Samsung’s and PG/Merchant’s servers

Create transaction

This API is used for creating transactions in the Web Checkout service. As shown in step #2 of Figure 1, this is the point of entry for service integration. You can get the fields shown in the table below from the response of this API, and they are used for calling Web Checkout SDK functions by entering them as arguments.

Response Field Description
id Created transaction ID
href Resource HREF (web URL) for accounting binding
encInfo.keyId RSA key ID
encInfo.mod RSA public key - modulus
encInfo.exp RSA public key - exponent

You can find the API specification in the ‘1.1 transaction.post – Create transaction to process’ chapter of the API specification document.

Get payment credentials

As shown in step #20 of Figure 2, this API is used for getting payment credential data generated in the user’s mobile device. This credential data is temporarily stored in the Samsung server after being generated, and then the Web Checkout UI is redirected to your Callback URL, with the Reference ID as a query parameter. (for example, https://your.callback.url?ref_id={referenceID}) Then, when your callback URL is called, your system can retrieve the Reference ID from the query parameters, and that Reference ID is used for the path parameter of this API call. (/ops/v1/transactions/paymentCredentials/{referenceId})

Response Field Description
3DS.data This field is payment credentials data encrypted by your CSR (public). After decrypting in your side, you can process the payment with Acquirer.

You can get many fields from the response of this API, one of them is 3DS.data. It is encrypted by your CSR (public), which uses JWE or JWE/JWS (without AAD), so you can decrypt it yourself, and process the payment with the Acquirer.

You can find the API specification in the ‘1.2 transaction.paymentCredential.get – Retrieve Payment Credential’ chapter of the API specification document. Also see the ‘8.1 Decrypting payment credentials data chapter, which describes sample codes for decrypting payment credential data by using your private key.

Notify payment result

As shown in step #26 of Figure 3 (pg. 9), this API is used to notify the Samsung Web Checkout server of the payment result. After processing the payment with the Acquirer, you can get the result from the Acquirer, and deliver it to the Samsung Web Checkout server with this API. The Reference ID is also used for one of the JSON fields in the request body when calling this API. The result status can be one of CHARGED, CANCELED, REJECTED, TIMEOUT, or ERRED.

You can find the API specification in the ‘2.1 notification.post – Notify the transaction result to Samsung’ chapter of API specification document.

Health check

A health check implementation is available for checking communication between the Samsung server and the PG’s or Merchant’s server. This functionality checks communication bidirectionally, so it is required to implement one part of this on the PG/Merchant side. The Health check is first triggered from the Samsung server to the PG/Merchant side. After this, the PG/Merchant checks the communication with the Samsung server and depending on the response, returns a final response to the Samsung server.

Health Check

For code examples, see the Configure the Health Check API chapter of the API specification document.


Getting started with the Web Checkout SDK

Including the Web Checkout SDK file

SamsungPayWeb CheckoutSDK is written byJavascript. So you can add it in your front-end view as below after uploading it in your resource path.

SDK for Development environment:

<scriptsrc="https://d35p4vvdul393k.cloudfront.net/sdk_library/us/stg/ops/pc_gsmpi_web_sdk.js"></script>

SDK for Production environment:

<scriptsrc="https://d16i99j5zwwv51.cloudfront.net/sdk_library/us/prd/ops/pc_gsmpi_web_sdk.js"></script>

Calling the 'connect' function

The SamsungPay Web Checkout SDK provides a connect function. You can get arguments of this function through the Create transaction API. That API response includes transaction ID, HREF, and encrypt information. Then you can retrieve those fields from the response, and then input them as function arguments.
This function checks whether the user’s browser is in a mobile or PC environment, and opens the Web Checkout UI page with encrypted data. You can call this function in the following way:

SamsungPay.connect( 
    Transaction ID, href, Service ID, Callback URL, Cancel URL, Country Code, PublicKey(Mod), PublicKey(Exp), Key ID
);
No Arguments Description
1 Tramsaction ID This is included in the response body of the Create transaction API, as id. Retrieve the id field in the response and input it as argument in here.

2 href This is included in the response body of the Create transaction API, as href. Retrieve the href field in the response and input it as argument in here.

3 Service ID Unique identifier for identifying your system in the Samsung Web Checkout service. It is used for the whole flow of the Web Checkout service. The Samsung team gives this value after partner onboarding in admin portal.
4 Callback URL This is the return URL after checkout payment is verified by user. When moving to this callback URL after user verification, the Samsung Pay Web checkout server adds the reference ID as a query parameter, called ref_id. (i.e. https://your.callback.url?ref_id={referenceID}). We also support one more option for delivering the reference ID. You can use a {refId} string anywhere in your callback URL, and the {referenceID} is inserted to the place as well. For example, if you insert your callback URL as ‘http://your.callback.url/{refId}/whatever’, the page would be redirected to ‘http://your.callback.url/{referenceId}/whatever?ref_id={referenceId}’.

5 Cancel URL This is the cancel URL for when the user cancels for the payment.
6 Country Code The default country code for when the checkout page is popped up. For example, if you set it to ru, the Web Checkout UI shows up in the Russian language when it pops up.

7 PublicKey(Mod) This is included in the response body of the Create transaction API, as ‘encInfo.mod’. Retrieve the encInfo.mod field in the response and input it as argument here.

8 PublicKey(Exp) This is also included in the response body of the ‘5.1 Create transaction’ API, aswhich is encInfo.exp in response. Just Rretrieve the ‘encInfo.exp’ field in the response and input it as argument in here.

9 Key ID This is included in the response body of the ‘Create transaction’ API, as encInfo.keyId. Retrieve encInfo.keyId field in the response and input it as argument here.


Country Code

The following table contains the list of current supported country codes.

Country code Description
en_ae UAE (English)
ae_ae UAE (Arabic)
au Australia (English)
br Brazil (Portuguese)
de_ch Switzerland (German)
en_ch Switzerland (English)
fr_ch Switzerland (French)
It_ch Switzerland (Italian)
hk Hong Kong (Chinese)
my Malaysia (English)
ru Russia (Russian)
se Sweden (Swedish)
sg Singapore (English)
tw Taiwan (Chinese)
uk UK (English)
us USA (English)
vn Vietnam (Vietnamese)

Sample code (ajax)

$.ajax({
  type: "POST",
  url: "./transactions",
  data: #API Request body in here,
  success: function (result) {
    SamsungPay.connect(
      result.id, result.href, serviceId, callback, cancel, countryCode,
      result.encInfo.mod, result.encInfo.exp, result.encInfo.keyId
    );	
  },
  error: function (result) {
  }
}); 

Ingetration test

If integration for the ‘Create transaction’ API and Web Checkout SDK is done well, you are ready to test the Web Checkout service and go to the next step. For the next step and integration testing, you can refer to below screen shot.
At step #6, you need to retrieve ‘ref_id’ from the query parameter and call the ‘Get payment credentials’ API for getting payment credential data. After getting it, you can process your own payment flow. Finally, if you get the payment result from the Acquirer, deliver it by calling the Notify payment result’API.

Payment Flow

Appendix A. Decrypting payment credentials data

A.1. Generate der file using your private key

$ openssl pkcs8 -topk8 -in Merchant.key -outform DER -nocrypt -out rsapriv.der

A.2. Decrypt JWE credential data

Sample code(Java)

import java.io.*;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import javax.crypto.*;
...
public static void main(String[] args) {
  String encPayload = {{encryptedPayload}};
  String privateKeyFilePath = "./rsapriv.der";
  getDecryptedData(encPayload, privateKeyFilePath);
}

public static String getDecryptedData(String encPayload, String privateKeyFilePath) {
  String delims = "[.]";
  String[] tokens = encPayload.split(delims);

  Decoder urlDecoder = Base64.getUrlDecoder();
  byte[] encKey = urlDecoder.decode(tokens[1]);
  byte[] iv = urlDecoder.decode(tokens[2]);
  byte[] cipherText = urlDecoder.decode(tokens[3]);
  byte[] tag = urlDecoder.decode(tokens[4]);
  byte[] plainText = new byte[cipherText.length];

  try {
    // Read private key file
    File privateKeyFile = new File(privateKeyFilePath);
    DataInputStream dis = new DataInputStream(new FileInputStream(privateKeyFile));
    byte[] privKeyBytes = new byte[(int) privateKeyFile.length()];
    dis.read(privKeyBytes);
    dis.close();

    // Set private key spec
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privKeyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privKey = keyFactory.generatePrivate(spec);

    Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    decryptCipher.init(Cipher.DECRYPT_MODE, privKey);
    byte[] plainEncKey = decryptCipher.doFinal(encKey);

    final Cipher aes128Cipher = Cipher.getInstance("AES/GCM/NoPadding");
    final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);
    final SecretKeySpec keySpec = new SecretKeySpec(plainEncKey, "AES");
    aes128Cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);

    int offset = aes128Cipher.update(cipherText, 0, cipherText.length, plainText, 0);
    aes128Cipher.update(tag, 0, tag.length, plainText, offset);
    aes128Cipher.doFinal(plainText, offset);
  } catch (Exception e) {
  }
  return new String(plainText);
}

Sample code
The following packages need to be installed for C# .netCore

Install-Package ChilkatDnCore -Version 9.5.0.69 (https://www.nuget.org/packages/ChilkatDnCore/)
Install-Package jose-jwt (https://www.nuget.org/packages/jose-jwt/)

using Jose;
using System;
using System.Text;
...
static void Main(string[] args)
{
  String encPayload = {{encryptedPayload}};
  String privateKeyFilePath = "./rsapriv.der";
  getDecryptedData(encPayload, privateKeyFilePath);
}

static void getDecryptedData(String encPayload, String privateKeyFilePath) {
  char delims = '.';
  string[] tokens = encPayload.Split(delims);
  byte[] header = Base64Url.Decode(tokens[0]);
  string headerString = Encoding.UTF8.GetString(header);
  Console.WriteLine("headerString: " + headerString);
  byte[] encKey = Base64Url.Decode(tokens[1]);
  byte[] iv = Base64Url.Decode(tokens[2]);
  byte[] cipherText = Base64Url.Decode(tokens[3]);
  byte[] tag = Base64Url.Decode(tokens[4]);
  byte[] plainText = new byte[cipherText.Length];

  Chilkat.Rsa rsa = new Chilkat.Rsa();
  bool success = rsa.UnlockComponent("Anything for 30-day trial");
  if (success != true) {
    Console.WriteLine(rsa.LastErrorText);
    return;
  }

  Chilkat.PrivateKey privateKey = new Chilkat.PrivateKey();
  success = privateKey.LoadPemFile(privateKeyFilePath);
  if (success != true) {
    Console.WriteLine(privateKey.LastErrorText);
    return;
  }

  success = rsa.ImportPrivateKeyObj(privateKey);
  if (success != true) {
    Console.WriteLine(rsa.LastErrorText);
    return;
  }

  rsa.EncodingMode = "base64";
  rsa.OaepPadding = false;
  bool usePrivateKey = true;
  byte[] plainEncKey = rsa.DecryptBytes(encKey, usePrivateKey);
  Console.WriteLine(
      "plainEncKey: " + Encoding.UTF8.GetString(plainEncKey) + ", size: " + plainEncKey.Length);

  AesGcmEncryption aesGcmEngine = new AesGcmEncryption(128);
  plainText = aesGcmEngine.Decrypt(null, plainEncKey, iv, cipherText, tag);
  Console.WriteLine("plainText: " + Encoding.UTF8.GetString(plainText));
}

Appendix B. Configure the Health Check API

Sample code(Java)

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.*;
import org.springframework.web.client.*;

@RestController
public class HealthCheckController {

    @Value("${ops.address}")
    private String onlinePaymentsAddress;

    @RequestMapping(method = RequestMethod.HEAD, value = "/samsungpay/integration/health")
    public ResponseEntity<Void> health() {

        String healthcheckAddress = onlinePaymentsAddress + "/ops/v1/internal/health";
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<Void> healthcheckResponse;

        try {
            healthcheckResponse = restTemplate.exchange(healthcheckAddress, HttpMethod.HEAD,
                    null, Void.class);
        } catch (RestClientException e) {
            return new ResponseEntity<>(HttpStatus.BAD_GATEWAY);
        }

        if (healthcheckResponse.getStatusCode() != HttpStatus.NO_CONTENT) {
            return new ResponseEntity<>(HttpStatus.BAD_GATEWAY);
        }

        return healthcheckResponse;
    }
}