Integration Guide

Step-by-step guide to integrate Berbix into your application.

Introduction

With this integration guide, we’ve made it as easy as possible to quickly get up and running with an end-to-end embedded Berbix integration. Please see our Hosted Flow if you're only looking to create unique links to share with your customers.

In this guide, you will:

  1. Create Test Transactions
  2. Initialize the Berbix Verify Flow
  3. Fetch Transaction Data
  4. Customize Berbix
  5. Move to Production

We recommend reading our Platform Overview for a look at key terms, concepts and a diagram of an end-to-end integration. Additionally, a sample open-source Ruby integration is available for review on our GitHub.

Create Test Transactions

To begin, you'll integrate the Berbix Verify API into your backend to start creating test transactions.

The Berbix Verify API can be called from any basic HTTP client. Berbix provides several Server-Side SDKs to simplify interactions with the API:

Constructing the Berbix Client

Before creating a transaction, you'll first need to construct the Berbix API client.

If you're using one of our Client-Side SDKs, you can initialize the Berbix client by following the example code below for your selected SDK. You'll need to include your test API Secret.

var berbix = require('berbix');

var client = new berbix.Client({
  apiSecret: '<<user>>',
})
require_once('/path/to/berbix-php/init.php');

$client = new \Berbix\Client(
  "<<user>>");
import berbix

client = berbix.Client(
  api_secret='<<user>>')
require 'berbix'

client = Berbix::Client.new(
  api_secret: '<<user>>',
)
BerbixClient berbixClient = Berbix.create(
    new Berbix.BerbixOptions.Builder()
        .apiSecret("<<user>>")
        .build());
import "github.com/berbix/berbix-go"

client := NewClient("<<user>>", &ClientOptions{})

📘

Where do I find my API Secret?

  1. Log in to the Berbix dashboard
  2. Make sure Test Mode is toggled ON*
  3. Select Integrations in the nav menu
  4. Tap Add Key or copy the existing key

More information about API Keys can be reviewed here.

*Please use the Test API secret when integrating Berbix in a non-production environment.

Creating a Transaction

To create a transaction, you just need to send a customerUid and templateKey along in the API request.

The customerUid should map to the primary identifier for the user in your internal systems, and the templateKey should map to the Berbix template you want to use to verify your user.

You will have a Default template for web integrations configured for a front & back ID check in your account by default. Please create a new template for native mobile integrations.

var transactionTokens = client.createTransaction({
  customerUid: "internal_customer_uid", // ID for the user in internal database
  templateKey: "<<template_key>>", // Template key for this transaction
})
$transactionTokens = $client->createTransaction(array(
  'customerUid' => "internal_customer_uid", // ID for the user in internal database
  'templateKey' => "<<template_key>>", // Template key for this transaction
));
transaction_tokens = client.create_transaction(
  customer_uid="internal_customer_uid", # ID for the user in internal database
  template_key="<<template_key>>", # Template key for this transaction
)
transaction_tokens = client.create_transaction(
  customer_uid: 'internal_customer_uid', # ID for the user in client database
  template_key: '<<template_key>>', # Template key for this transaction
)
CreateTransactionRequest request = new CreateTransactionRequest();
request.customerUid = "internal_customer_uid"; // ID for the user in internal database
request.templateKey = "<<template_key>>"; // Template key for this transaction

CreateTransactionResponse response = berbixClient.createTransaction(request);
tokens, err := client.CreateTransaction(&CreateTransactionOptions{
    CustomerUID: "internal_customer_uid", // ID for the user in client database
    TemplateKey: "<<template_key>>", // Template key for this transaction,
})

An access_token, client_token, and refresh_token will be returned in the response as shown in the example below.

Please refer to the Create transaction reference documentation for a full request and response format specification.

{
"transaction_id":5689410907470336
"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dsfsWQiOjU2NzYwNDE5MDc0NzAzMzYsImNpZCI6NTYzNDQ3MjU2OTQ3MDk3Niw"
"refresh_token":"x9iBVHQUVqx9sHGjRyTAEBOdsD23Wxld"
"expires_in":3600
"token_type":"Bearer"
"client_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ8dsdfsaWQiOjU2NzYwNDE5MDc0NzAzMzYsImNpZCI6NTYzNDQ3MjU2OTQ3MDk3Niw"
}

Tokens

Interacting with the Berbix API involves 3 types of tokens:

client token

  • Needs to be passed to your front end to initialize the verification flow for your end-user
  • Expires after 1 hour

access token

  • Will be used to fetch transaction metadata once your end-user completes the verification flow
  • Expires after 1 hour

refresh token

  • Can be used to fetch a new client_token to resume an incomplete transaction.
  • Can be used to regenerate an access_token in the future for fetching, updating or deleting transaction data
  • Does not expire until the transaction is deleted manually in the dashboard, programmatically via the API, or automatically via retention policy

👍

Refresh Token Best Practice

Always store the refresh_token in your application database associated with the respective customerUid.

Reusing transactions

📘

Keep in Mind!

Every time the create_transaction endpoint is called, a new transaction is created.

This is the case even if the endpoint is called with the same customer_uid, since we allow for multiple transactions for a given customer_uid.

We recommend including a server-side check when creating a transaction to see if an incomplete transaction exists for a given user before calling create_transaction.

If an incomplete transaction already exists, you should use its refresh_token to create a new client_token in order to re-start the incomplete transaction.

This allows the end-user to pick up where they left off in the initial transaction rather than starting over. Additionally, this keeps your Berbix dashboard clear of excess incomplete transactions, making it easier to review results and investigate issues.

👍

Remember!

Keep track of the refresh_token for each transaction you create.

If you're planning to allow users to retry verifying with Berbix after completing an initial transaction, keep track of the refresh_token of both the initial and subsequent transactions to maintain a one-to-many relationship between users and Berbix transactions.

This maximizes the amount of data you'll have available for debugging your integration and potentially investigating fraud on your platform.

❗️

Exception!

In order to successfully reuse transactions, subsequent transactions must be on the same platform as the initial.

Ex: If the initial transaction used a Web template type, the transaction cannot be reused for a subsequent transaction with a Native Mobile template type.

Creating hosted transactions

In order to create a hosted transaction, you'll need to include the hosted_options parameter in your Create transaction request. This parameter can be an empty object (hosted_options={}) if you don't require additional configuration.

When provided, Berbix will return a hosted verification link that is unique to each transaction in the hosted_url response field.

Initialize the Berbix Verify Flow

There are several ways you can integrate the Berbix identity verification flow into your application.

In addition to Basic JavaScript, Berbix provides the following Client-Side SDKs across web and mobile:

Basic JavaScript

When your page loads, you should create a handler via BerbixVerify.configure(). The verification flow can then be initialized by calling open() on the handler in response to any user events. The simple example below initializes the Berbix flow when a user clicks the Verify Me button.

Upon completion of the verification flow, Berbix will trigger the onComplete callback that can be used to advance the user through your application. Berbix will invoke the onError callback if the verification fails for any reason and the onExit when someone closes the Berbix modal.

<button id="myButton">Verify Me</button>

<script src="https://sdk.berbix.com/latest/berbix-verify.js"></script>

<script>
  var handler = BerbixVerify.configure({
    onComplete: function() {
    },
    onExit: function() {
    }
  });

  document.getElementById('myButton').addEventListener('click', function(e) {
    handler.open({
      clientToken: 'your_client_token',
      modal: 'true'
    });
  });
</script>

Configuration

Required

  • clientToken: A token returned after creating a transaction that connects your frontend with the associated transaction metadata. This allows a user to perform incremental verification in addition to any previously completed verifications. A client token can be regenerated using Create access token if necessary.
  • modal: This value should be set to true unless you intend to use Berbix in an embedded element on the page rather than a modal invoked after button click. To use Berbix in an embedded element on the page, use the root attribute to specify the ID of the root div in which Berbix should be embedded.

👍

Modals are your friend!

We recommend using the modal option for most web integrations. The Berbix Verify Flow will generally perform best when it can use the entirety of the vertical space available on the screen, especially on mobile browsers and smaller screens.

By using the modal option, you avoid having to worry about the way the design of your website might interfere with the rendering of the Berbix Verify Flow on various devices.

  • onComplete: The callback invoked when Berbix Verify completes.
  • onExit: The callback invoked when a user exits or closes the Berbix Verify modal. Required when using the modal experience.

Optional

  • onDisplay: The callback invoked when Berbix Verify is visible to the user. This is useful for removing loading states or hiding other elements.
  • onError: The callback invoked when verification fails. It is passed any reason for failure as a parameter.
  • showCloseModalButton (bool): Whether or not there should be a close button on the Berbix Verify modal.

🚧

Allowlist domains serving Berbix

You'll need to add the domains from which you expect to serve Berbix Verify when initializing the frontend flow. Please see our domains documentation for instructions.

🚧

Avoid re-instantiating the Berbix Verify Flow after a transaction has been completed

As a general rule, you should avoid re-instantiating the Berbix Verify Flow after a transaction has been completed. Instead, you should keep track of whether transactions are completed or not in your database, and only instantiate the Berbix Verify Flow if a transaction has not been completed yet.

If you rely on the onComplete callback in order to determine whether a transaction has been completed, you risk significant latency due to loading the Berbix Verify Flow and passing the requisite data from your client to your backend. Moreover, doing so puts unnecessary load on Berbix's infrastructure.

See Fetch Transaction Data and Receive Actions via Webhooks below for more information on how to access a transaction's result post-completion.

Fetch Transaction Data

Once a verification completes, you'll need to consume the metadata about a transaction to determine next steps for your end-users.

Create Access Token from Refresh Token

To fetch metadata for a given transaction, you first need an access_token for the associated transaction. A short-lived access_token is returned in the transaction creation response but you'll often need to regenerate the access_token for later requests.

If you're using one of our Server-Side SDKs, you can utilize the example code below for your selected SDK. You'll need to load the transaction's refresh_token from your application database.

refreshToken = ''; // fetched from database
// Load refresh token from database into a Token object
const transactionTokens = berbix.Tokens.fromRefresh(refreshToken);

// Call Berbix API to exchange refreshToken for fresh tokens. 
// This is typically not needed to be called explicitly as it will be called 
// by the higher-level SDK methods, but can be used to get fresh client or 
// access tokens.
const refreshedTokens = client.refreshTokens(transactionTokens);
$refreshToken = ''; // fetched from database
// Load refresh token from database into a Token object
$transactionTokens = new \Berbix\Tokens::fromRefresh($refreshToken);

// Call Berbix API to exchange refreshToken for fresh tokens. 
// This is typically not needed to be called explicitly as it will be called 
// by the higher-level SDK methods, but can be used to get fresh client or 
// access tokens.
$refreshedTokens = $client->refreshTokens($transactionTokens)
refresh_token = '' # fetched from database
# Load refresh token from database into a Token object
transaction_tokens = Tokens.from_refresh(refresh_token)

# Call Berbix API to exchange refreshToken for fresh tokens. 
# This is typically not needed to be called explicitly as it will be called 
# by the higher-level SDK methods, but can be used to get fresh client or 
# access tokens.
refreshed_tokens = client.refresh_tokens(transaction_tokens)
refresh_token = '' # fetched from database
# Load refresh token from database into a Token object
transaction_tokens = Berbix::Tokens.from_refresh(refresh_token)

# Call Berbix API to exchange refreshToken for fresh tokens. 
# This is typically not needed to be called explicitly as it will be called 
# by the higher-level SDK methods, but can be used to get fresh client or 
# access tokens.
refreshed_tokens = client.refresh_tokens(transaction_tokens)
refreshToken := "" // fetched from database
// Load refresh token from database into a Token object
transactionTokens := TokensFromRefresh(refreshToken)

// Call Berbix API to exchange refreshToken for fresh tokens. 
// This is typically not needed to be called explicitly as it will be called 
// by the higher-level SDK methods, but can be used to get fresh client or 
// access tokens.
refreshedTokens, err := client.RefreshTokens(transactionTokens)

If you're not using one of our Server-Side SDKs, you'll need to make a request including the refresh_token to the /tokens endpoint and the associated access_token will be included in the response.

Complete documentation for the Berbix /token endpoint is available in our API reference.

Fetch Transaction Data

After generating the access_token, you'll then pass this to the /transactions endpoint to get all associated transaction data.

If you're using one of our API Libraries, you can reference the code samples below. Otherwise, please refer to our Get transaction verifications API spec.

var transactionData = await client.fetchTransaction(transactionTokens)
$transactionData = $client->fetchTransaction($transactionTokens);
transaction_data = client.fetch_transaction(transaction_tokens)
transaction_data = client.fetch_transaction(transaction_tokens)
transactionData, err := client.FetchTransaction(transactionTokens)

All data for the given transaction will be returned in the response as shown in the example below. A complete list of properties returned is defined in our API Reference.

{
  "action": "reject",
  "addons": null,
  "created_at": "2019-07-02T21:18:43Z",
  "customer_uid": "123456789",
  "dashboard_url": "https://dashboardberbix.com/transaction?orgId=123456789&transactionId=123456789123",
  "duplicates": [...],
  "flags": [...],
  "fields": [...],
  "images": {...}
}

Most importantly, you'll want to consume the action value (accept, reject, review, or a custom action) to determine next steps for your verified end-user.

🚧

Avoid strict enums that cause fatal errors

From time to time, Berbix might incorporate new values in its API responses, typically to enable access to new features. For example, we might introduce new options for flags, or additional fields.

Unlike removals of existing values, we consider these changes to be non-breaking and typically do not version our API when we make them.

As a result, we strongly suggest that you build your integration in a way that is robust to such changes. In particular, you should avoid strict enums that would result in a fatal error being thrown in the presence of a novel value. Instead, you should make sure to handle the error in a way that ensure that you can "fail open" in the event that new values are introduced in Berbix's API response.

We recommend relying on the action value for your business logic based on a customized Action Map. You may also retrieve and reference the raw flags (id_fake_likely, id_under_18, etc.) or the fields data (address, date_of_birth, cropped_front_url, etc.) returned from the transaction.

Receive Actions via Webhooks

Alternatively, you may receive the transaction ID and the determined action via a webhook when verification is complete. Please see our webhook docs to implement.

❗️

Do not poll the Berbix API

You might be tempted to design your integration such that it would "poll" the Berbix API while waiting for a transaction's completion by querying the Berbix API at regular interval. Because of the drain it can put on Berbix's infrastructure, that style of integration is not supported by Berbix, and might cause our automated abuse prevention systems to interfere with your ability to access transactions.

Rather than polling, please either wait for the onComplete callback to be triggered client-side before querying our API, or use a server-side webhook.

Naturally, you should feel free to design your system such that it retries any failed API requests (e.g. in the event that you encounter network connectivity issues, or in the rare event that Berbix is not reachable). If you decide to do so, we strongly recommend the use of exponential backoff in your implementation of your retry logic.

Updating transactions

If your desired workflow involves reviewing completed transactions internally, you may want to send the updated action back to Berbix.

This can be accomplished using our API with the Update an existing transaction endpoint.

Deleting transactions

Our API provides an endpoint for programmatically deleting transactions. Our API libraries also include helpers for calling that endpoint.

The ability to programmatically delete transactions is provided primarily as a means to deal with certain testing and compliance edge cases (e.g. to comply with a request from one of your users to delete all of their data from all of your systems). We generally do not recommend deleting transactions in the normal course of usage of Berbix.

Deleting transactions shortly after their completion could additionally limit your ability to diagnose issues with your integrations, and Berbix's own ability to provide you with support. In general, if you're hoping to delete transactions in a regular fashion, we recommend that you rely on our automated retention policies, which can be set to be as short as 7 days.

📘

Allowing users to re-verify with Berbix

If you're thinking of deleting transactions as a means to enable your users to retry verifying their ID after having failed, you might consider storing the reference to the most recent Berbix transaction in a one-to-one relationship with your representation of your users.

Rather than doing that, we suggest you instead consider enabling a one-to-many relationship between the representation of your users in your database and that of Berbix transactions. Indeed, by enabling a one-to-many relationship between users and Berbix transactions, you maximize the amount of data you'll have available for not only debugging your integration, but also potentially investigating fraud on your platform.

Customize Berbix

You've now built a fully functional end-to-end Berbix integration! Before moving to production, you'll want to customize the required verification steps, the look-and-feel, and the business logic behind your integration.

Custom Template

Templates control the experience for your end-users and enable you to specify differing levels of verification required for different user account types. Templates include the types of verification you'd like to conduct (photo ID, selfie, etc.) and settings for the verification flow (number of attempts, timeouts, etc.). At a minimum, you should decide what types of IDs are allowed as well as if you need to require a selfie image and liveness check.

Custom Theme

You optionally may want to create a custom theme associated with your template(s). Themes configure the look-and-feel of your verification flow. Theme customization is currently only supported for web templates.

Action Map

Action maps allow you to customize the business logic associated with Berbix transactions. By default, Berbix provides three actions: reject, review, and accept. Review Queues are populated by review actions. If appropriate for your use case, custom actions can be added.

The determined action after a verification will be returned in the transaction metadata and exposed in the Berbix Dashboard for a given transaction.

Move to Production

At this point, you'll be able to test a fully customized Berbix flow in your own application. Please refer to our Testing Guide for instructions on how to best test Berbix end-to-end. Assuming all goes well, you can move your integration to production by simply replacing your Test API Secret with a corresponding Live value.

You'll need to accept our terms and subscribe to Berbix before gaining access to live mode. Please don't hesitate to contact us if you have any questions!

© Berbix Inc. All rights reserved.