Zlick SDK Integration Guide

Zlick SDK offers marketplaces, newspapers and other commerce platforms a powerful and flexible mobile payment solution.

Getting Started

To get started, request your development account and development SDK by emailing to support@zlick.it. You will receive your client token and client secret which will be needed to integrate Zlick SDK on your website.

Integration Flow

Here is a basic overview of how you can use Zlick SDK to control paid access to content in your site:

Zlick Integration Flow

Add the SDK to your website

Add Zlick SDK to your website after your own scripts.

<head>
  <script type='text/javascript' src='path/to/your/javascript/files/index.js'></script>
  <!-- Dev SDK -->
  <script type='text/javascript' src='https://cdn.zlick.it/zlick-dev-2.5.2.js'></script>
  <!-- OR the live SDK -->
  <script type='text/javascript' src='https://cdn.zlick.it/zlick-2.5.2.js'></script>
</head>

Once you've included the SDK, the SDK exposes a global variable called zlick. You will be abke to use this object to call zlick methods.

Important Note About JWT tokens

Many of the methods below use JWT tokens as function inputs. Instructions to generate these JWT tokens can be found here.

API

identifyClient(token)

Before you do any kind of operation with Zlick SDK, you have to call the identifyClient method. This method attempts to authenticate the current user and returns information about the user that you will need for calling other methods later.

Parameters

Response

See standard response

Examples

When user is not found
{
  phone: null,
  userId: null,
  contentId: null,
  hasAccessRights: false,
  allowedMethods: {
    smsAuth: true
  },
  jwtToken: "xxxxxxx.xxxxxxxxxx.xxxxxxx"
}
When IP billing has been detected

When IP billing is detected for the current visitor, we have 2 additional fields: * challengeId is used in combination with subscribeByChallengeId() * authMethod tells which authentication method is available, in this case CARRIER_PROXY

{
  phone: null,
  userId: null,
  contentId: null,
  hasAccessRights: false,
  authMethod: "CARRIER_PROXY",
  challengeId: "xxxxxxxx",
  allowedMethods: {
    smsAuth: true
  },
  jwtToken: "xxxxxxx.xxxxxxxxxx.xxxxxxx"
}

IP Billing flow basic structure

This is a sample structure how to implement the IP billing flow.

const subscriptionToken = 'JWT.TOKEN'
const { 
  AUTH_TYPES,
  CHALLENGE_STATUS,
  checkIpBillingStatus,
  sendPinCodeSMS,
  verifyPinCode,
  subscribeByChallengeId
} = zlick


window.onload = async function () {
  const identifyResponse = await zlick.identifyClient(subscriptionToken);
  // this will authenticate and make autopurchase
  if (identifyResponse.authMethod === AUTH_TYPES.CARRIER_PROXY) {
    // DO some UI stuff, e.g. show button and explain that it 
    drawSubscribeButton(identifyResponse)
    return
  }
  drawSMSAuthButton()
}

function drawSubscribeButton(identifyResponse) {
  // HTML5 UI
  const { challengeId } = identifyResponse
  const buttonElement = document.getElementById('subscribe-button')
  buttonElement.onclick = () => {
    handleSubscribeButtonClicked({ challengeId, token: subscriptionToken })
  }
}

function drawSMSAuthButton() {
  // HTML 5 UI
  const mobilePhoneNumber = document.getElementById('sms-auth-phoneNumber').value
  const buttonElement = document.getElementById('send-pin-button')
  buttonElement.onclick = () => {
    handleSendPinCodeSMSClicked({ mobilePhoneNumber, token: subscriptionToken })
  }
}

function handleSubscribeButtonClicked ({ challengeId, token }) {
  // opens a popup and waits until the challenge response is received
  const challengeResponse = await subscribeByChallengeId({ challengeId, token })
  updateUIByChallengeResponse(challengeResponse)
}

function handleSendPinCodeSMSClicked({ mobilePhoneNumber, token }) {
  // before continuing with the regular flow, let's check it it is a IP billing
  const sendPinCodeSMSResponse = await sendPinCodeSMS({ mobilePhoneNumber, token })
  if (sendPinCodeSMSResponse.authMethod === AUTH_TYPES.CARRIER_PROXY) {
    const challengeResponse = await checkIpBillingStatus({ challengeId: sendPinCodeSMSResponse.challengeId })
    updateUIByChallengeResponse(challengeResponse)
    return
  }
  // here goes the regular flow
}


function updateUIByChallengeResponse(challengeResponse) {
  if (challengeResponse.status === CHALLENGE_STATUS.ACTIVE) {
    // show content
  }
  if (challengeResponse.status === CHALLENGE_STATUS.FAILED) {
    // show failed message
  }
  if (challengeResponse.status === CHALLENGE_STATUS.EXPIRED) {
    // show expired message
  }
}

purchase(params)

Initializes one time purchase. Returns success, failure or need for SMS authentication

Parameters

Response

See standard response

subscribe(params)

Subsribes to monthly / weekly / daily subscription. When you sign up as a client with Zlick, you have to pre-define your subscription plans with unique names. While calling this method with a subscribe JWT token, you have to reference the unique product name. Zlick will use additional information about that subscription product from its own database.

For more information about subscriptions, see subscriptions flow.

Parameters

Response

See standard response

subscribeByChallengeId(params)

Subsribes to a monthly / weekly / daily subscription by challengeId. This method is when the IP Billing is detected automatically by identifyClient call. In this case the identifyClient will have additional fields for that, see when ip billing has been detected

Parameters

Response

See ip billing response

checkIpBillingStatus(params)

Checks the status of the IP billing by challangeId. Use this method when sendPinCodeSMS(params) sendPinCodeSMSResponse.authMethod has AUTH_TYPES.CARRIER_PROXY, see auth types

Parameters

Response

See ip billing response

sendPinCodeSMS(params)

Starts SMS authentication by sending SMS with a pin code to user. Use this when userId is returned as null from identifyClient call.

In case the IP billing is detected, the response is different here. See ip billing flow

Parameters

Response

See standard response

Response when using IP billing

See ip billing response

verifyPinCode(params)

Completes SMS authentication flow and returns userId on success. Throws an error on failure. See Errors.

Parameters

Response

See standard response

refundPurchase(params)

Completes SMS authentication flow and returns userId on success. Throws an error on failure. See Errors.

Parameters

Response

See standard response

unsubscribe(params)

Completes SMS authentication flow and returns userId on success. Throws an error on failure. See Errors.

Parameters

Response

See standard response

setCookie(cookieObject)

This method sets zlick cookie in the browser. This is useful in some scenarios when moving from v1 SDK to v2 SDK while keeping existing users logged in.

If the v1 cookie is detected, the content provider can convert the v1 cookie to v2 on their server side, and after that they can set the cookie for v2 with this method.

So from the client perspective, the process is as follows: 1. In the browser app, you need to check if there exists a cookie named zlick with a value that contains userId 2. If the userId if found, you can generate the new userIdToken on your server side like so:

POST /my-api/getcookie with body userId
jwt.sign({
  "apiClientToken": "7390d36701b0c29d8f8d3016af707ce9",
  "userId": "708fe1fe-864a-4ef4-8dab-cbf930f7a545",
}, secret)
  1. Now it is possible to override the cookie with setCookie method and it should be done before calling the identifyClient method.

Parameters

Response

This function runs synchronously and returns undefined.


Standard Response

All Zlick methods return a Promise that resolves to the following object with some properties conditional on the method being called.

{
  userId: "123456abcdef", // zlick user id.
  phone: "1223774963",
  jwtToken: "xxxxxxx.xxxxxxxxxx.xxxxxxx",
  contentId: "123456abcdef", // purchased content or product name
  transactionId: "123456abcdef", // TransactionID, only present in case of transaction
  subscriptionId: "123456abcdef", //  subscriptionID, only present in case of subscription
  challengeId: "123456abcdef", //  challengeID, only present in case of sendPinCodeSMS
  hasAccessRights: "true", // Boolean. Shows if user has access to content
  allowedMethods: {
    refundPurchase: true
  } // object describing next allowed methods
}

IP Billing response

IP billing response when successful

{
  status: "active",
  subscription: {
    userId: "xxxxxxxx-xxxxxxxxx-xxxx-xxxxxxxxxxxx",
    phone: "35800000000",
    state: "active",
    subscriptionExpiresAt: "2020-02-01T00:00:00.000Z",
    validFrom: "2020-01-01T00:00:00.000Z"
  },
  userIdToken: "xxxxxxx.xxxxxxxxxx.xxxxxxx"
}

IP billing response when failed or expired

{
  status: "failed", // possible values: failed, expired
  subscription: null,
  userIdToken: null
}

IP billing flow

Zlick IP Billing Flow

When IP billing is detected the sendPinCodeSMS will have the following steps:

  1. User will be sent an SMS link instead of PIN code
  2. User clicks to the link
  3. The user will be asked to authetnicate and make the purchase
  4. If user clicks "decline", the authentication and transaction will fail
  5. If user clicks "accept", the authentication and transaction will succeed

Constants and Enums

CHALLENGE_STATUS

IP billing statuses

Values

Example

const response = getExampleResponse(...)
const { CHALLENGE_STATUS } = zlick

if (response.status === CHALLENGE_STATUS.ACTIVE) {
  // do stuff
}

AUTH_TYPES

Authentication types. Used to check which flow to go

Values


Errors

Error status codes

When a zlick method fails it throws an error with serveral properties. One being the statusCode, this will follow the standard HTTP error codes. Usually status codes reflect a general or broader category of the error. To identify more specific reasons for the failure, please check the additional property zlickErrorCode.

Zlick error codes

When purchase fails due to infufficent funds or for some other reason Zlick will always return the error with a unique zlickErrorCode. Please see below what each code implies.

We try to deliver more context of the exact error and so we will always try to summarize the error with a descriptive reason in the message property of the error.

SDK Demo

A demo solution is over here. You will not be charged for actions you perform there.