ShopBack In-Store Payments API

This guide provides payment partners and merchants with the steps necessary to integrate ShopBack Pay and ShopBack PayLater, enabling customers to pay using merchant-presented QR codes with existing in-store point-of-sale (POS) systems.

The ShopBack In-Store Payments API consists of a set of RESTful API endpoints and the sections below outline their usage, including request and response parameters.

Follow the steps in this guide to successfully integrate and certify your POS terminals to start accepting ShopBack QR Code payments with ease.

Prerequisites

Before using the APIs listed in this document, payment partners and merchants must be onboarded with ShopBack. During onboarding, the following credentials will be provided to you:

  • accessKeySecret - A secret key used to generate HMAC signatures for API requests.
  • accessKeyId - An identifier for accessKeySecret.

In addition, each POS terminal will be issued the following set of credentials:

  • posId - Unique ID for each POS terminal that will be generated by ShopBack.

Flow Diagram

ShopBack provides 2 ways of In-Store payments, Merchant Presented QR Code and Consumer Presented QR Code. As a merchant you can choose which one is your preferred method.

API Contract

Note: Only relative urls are provided at the moment.

Change Log

Document versionDate introducedChanges made
v1.111 Aug 2022Support both Pay and PayLater
v1.222 Aug 2022Add clarifying text for referenceId, use ISO-3166-1 Alpha for country code
v1.31 Sept 2022Surface HTTP 409 codes, show partnerId as not part of query param
v1.41 Jan 2023Add Consumer Presented Qr Code Endpoints
v1.57 Sep 2023Add POSI AU API Environment

API Environment

Authentication

All requests in this API specification require HMAC signatures in order to successfully authenticate API requests.

Generating an HMAC Signature

The HMAC-SHA256 algorithm must be used to generate a request signature, which is calculated using your accessKeySecret ​key.

  1. Create a content digest for your request body. The keys within the request body should be ordered alphabetically before the digest is generated.
contentDigest = sha256(stringify(requestBody));

2. Generate the string to sign by combining HTTP method, request content type, date-time in ISO-8601 format (also required in header params), fully qualified request path with query parameters (if any), and the content digest (from step 1) with a newline in between each parameter.

Note: Please follow this specific ordering of parameters.

POST
application/json
2022-08-22T02:29:33.123Z
https://integrations-sandbox.shopback.com/posi-sandbox/v1/instore/order/create
a4c198145e81b2904788cf3bb0385276b15962903b1a0d8de0ccf57909cf38bc

3. Sign this string with your accessKeySecret.

4. Generate hex encoded string from step 3 to generate hmac_signature

5. Attach the HMAC Signature in the Authorization header in this format SB1-HMAC-SHA256 accessKeyId:hmac_signature.

Example Code

const crypto = require('crypto');
const _ = require('lodash')
const ACCESS_KEY_SECRET_EXAMPLE = 'f33679f2ae892fd89ceefc409934e49f';

function createSHA256Digest(sortedBody) {
  if (_.isEmpty(sortedBody)) {
    return '';
  }
  const hash = crypto.createHash('sha256');
  hash.update(JSON.stringify(sortedBody));
  return hash.digest('hex');
}

function createHmacSignature(str, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(str);
  return hmac.digest('hex');
}

function computeRequestSignature(req, secret) {
  const { method, pathWithQuery, body, contentType, date } = req;
  const contentDigest = createSHA256Digest(body);
  const payload = `${method.toUpperCase()}\n${contentType}\n${date}\n${pathWithQuery}\n${contentDigest}`;
  return createHmacSignature(payload, secret);
}

function  alphabeticallySortBody(body: object) {
    return Object.keys(body)
      .sort()
      .reduce(
        (acc, key) => ({
          ...acc,
          [key]: body[key],
        }),
        {},
      );
  }

function main() {
  // Date should be specified in ISO 8601 UTC. Do not specify the time offset 
  // '2022-08-15T14:59:47.585Z' ✅
  // '2022-08-15T22:59:47.585Z+08' ❌
  const date = new Date().toISOString(); // to be used for Header param too. 
  
  const body = {
      referenceId: '352c530dd7f747161a5e6c990c720bec',
      currency: 'THB',
      posId: '802c987em7f747269a5e6c260c630kpl',
      amount: 1000,
    }
  const sortedBody = alphabeticallySortBody(body)
  // alphabetically-ordered keys in sortedBody 
  //  {
  //     amount: 1000,
  //     currency: 'THB',
  //     referenceId: '352c530dd7f747161a5e6c990c720bec',
  //     posId: '802c987em7f747269a5e6c260c630kpl',
  //   }

  const req = {
    method: 'POST',
    pathWithQuery: ' https://integrations-sandbox.shopback.com/posi-sandbox/v1/instore/order/create',
    body: sortedBody,
    contentType: 'application/json',
    date,
  };

  console.log(
    'hmac_signature: ',
    computeRequestSignature(req, ACCESS_KEY_SECRET_EXAMPLE),
  );
}

main();