# zkKYB - Know Your Business

## Use Case

To reduce development costs, you can use the zkMe KYB Widget to handle the entire business verification process. Users can complete the full KYB verification directly on your web/H5 application, minimizing user churn by eliminating the need to navigate to another page.

***

## zkMe KYB Widget Process

The KYB verification flow consists of the following steps:

**Step 1**: Enter the service authorization Widget page; the user confirms and proceeds to the next step.

**Step 2**: Email verification login.

**Step 3**: Fill in company basic information.

**Step 4**: Fill in UBO (Ultimate Beneficial Owner) / SMO (Senior Managing Official) information.

**Step 5**: Trigger controller KYC/PoA verification for each controlling person.

**Step 6**: Upload corporate documents.

**Step 7**: Submit for review. The application status will then move to "Info Submitted" and await manual review by the zkMe compliance team.

***

## Integration via NPM

You can refer to [@zkmelabs/kyb-widget](https://www.npmjs.com/package/@zkmelabs/kyb-widget) and please make sure to use the latest version.

### Installation

```sh
pnpm add @zkmelabs/kyb-widget

# or
yarn add @zkmelabs/kyb-widget

# or
npm install @zkmelabs/kyb-widget
```

### Getting Started

#### **Step 1. Import styles**

```typescript
import '@zkmelabs/kyb-widget/dist/style.css'
```

#### **Step 2. Create a new** `ZkMeKybWidget` **instance**

{% code expandable="true" %}

```typescript
import { ZkMeKybWidget, type Provider } from '@zkmelabs/kyb-widget'

const provider: Provider = {
  async getAccessToken() {
    // -------------------------TODO-------------------------
    // Request a new token from your backend service and return it to the widget.
    // For the access token, see https://docs.zk.me/hub/start/onboarding/integration/js-sdk/zkkyb#access-token
    // ------------------------------------------------------
    return fetchNewToken()
  },

  async getExternalID() {
    // -------------------------TODO-------------------------
    // `ExternalID` represents the unique identifier of this user in your system.
    // Typical examples include a corporate e-mail address, phone number,
    // or an internal user ID. Use the same identifier consistently
    // whenever you query or verify this user's KYB status.
    // ------------------------------------------------------
    return [externalID]
  },

}

const zkMeKybWidget = new ZkMeKybWidget(
  // -------------------------TODO-------------------------
  appId, // This parameter means the same thing as "mchNo"
  'YourDappName',
  provider,
  {
      programNo: 'YourProgramNo' // You can find the Program No in the ‘Configuration’ section of your KYB dashboard
      // For other options, please refer to the table below
  }
  // ------------------------------------------------------
)
```

{% endcode %}

{% hint style="info" %}
**NOTE:** The specific configuration for the "option" parameter is shown in the table below
{% endhint %}

<table><thead><tr><th width="195">Param</th><th width="164">Type</th><th>Description</th></tr></thead><tbody><tr><td>options.programNo</td><td>string</td><td><p>If you have activated multiple programs running in parallel, please pay attention to this setting:<br></p><p>The param can be found in Dashboard and please make sure the program is enabled. The SDK will take the number of the first activated program as the default value if this parameter is not provided in the code.</p></td></tr></tbody></table>

#### **Step 3. Listen to the `kybFinished` widget events to detect when the user has completed the zkKYB process.**

<pre class="language-typescript"><code class="lang-typescript">function handleKybFinished(results) {
  const { status, externalID, zkMeAccount, programNo } = results

  if (status === 5 &#x26;&#x26; externalID === provider.getExternalID().toLowerCase()) {
    // -------------------------TODO-------------------------
    // The user has successfully completed zkKYB verification.
    // Prompt the user that verification has been completed.
    // ------------------------------------------------------
    console.log(`KYB verification completed for ${externalID}`)
  }
}

<strong>zkMeWidget.on('kybFinished', handleKybFinished)
</strong></code></pre>

**Event Callback Parameters**

The `kybFinished` event callback receives a `results` object with the following properties:

<table><thead><tr><th width="186">Name</th><th width="83">Type</th><th>Description</th></tr></thead><tbody><tr><td>status</td><td>int</td><td><p>Indicates the current verification status of the KYB process.</p><p></p><p>Status codes are defined as follows:</p><ul><li><code>1</code> – Verification Started</li><li><code>2</code> – Info Submitted</li><li><code>3</code> – Under Review</li><li><code>4</code> – Resubmission Required</li><li><code>5</code> – Verification Passed</li><li><code>6</code> – Verification Failed</li></ul></td></tr><tr><td>externalID</td><td>string</td><td>The entity identifier from your system, echoed back by the SDK. This is the same value you returned as <code>externalID</code> in the <code>getExternalID()</code> function (for example, a corporate email address, phone number, or an internal user ID).</td></tr><tr><td>zkMeAccount</td><td>string</td><td>The zkMe internal account identifier.</td></tr></tbody></table>

#### **Step 4. Launch the zkMe KYB widget and it will be displayed in the center of your webpage.**

```typescript
// This is the code to launch our widget on your page
button.addEventListener('click', () => {
  zkMeKybWidget.launch()
})
```

***

## Helper functions

### verifyKybWithZkMeServices()

Before launching the widget, you should check the zkKYB status of the user and launch the widget when the check result is `false`.

{% tabs %}
{% tab title="Function" %}

```typescript
import { verifyKybWithZkMeServices } from '@zkmelabs/kyb-widget'

// zkKYB
const { status, statusDesc } = await verifyKybWithZkMeServices(
  appId, // Your unique App ID (mchNo)
  externalID, // The user's unique identifier (e.g., corporate email)
  accessToken, // The access token obtained from https://docs.zk.me/hub/start/onboarding/integration/js-sdk/zkkyb#access-token
  options // Optional configurations are detailed in the table below
)
```

<table><thead><tr><th width="192">Name</th><th width="89">Type</th><th>Description</th></tr></thead><tbody><tr><td>appId</td><td>string</td><td>This parameter means the same thing as "mchNo"</td></tr><tr><td>externalID</td><td>string</td><td>The unique identifier provided by you to reference the KYB entity to be verified. This should match the <code>getExternalID()</code> passed by <code>provider.getExternalID</code>.</td></tr><tr><td>accessToken</td><td>string</td><td>The access token obtained from <a data-mention href="#how-to-generate-an-access-token-with-api_key">#how-to-generate-an-access-token-with-api_key</a></td></tr><tr><td>options.programNo</td><td>string?</td><td>If you have activated multiple programs running in parallel, please pay attention to this setting:<br><br>The param can be found in Dashboard and please make sure the program is enabled. The SDK will take the number of the first activated program as the default value if this parameter is not provided in the code.</td></tr></tbody></table>
{% endtab %}

{% tab title="Return" %}

#### **Return Value**

The function returns an object with the following property:

<table><thead><tr><th width="184">Property</th><th width="96">Type</th><th>Description</th></tr></thead><tbody><tr><td>status</td><td>int</td><td>The current verification status as an integer. See the status codes table below.</td></tr><tr><td>statusDesc</td><td>string</td><td>A human-readable description of the current verification status.</td></tr></tbody></table>

**Status Codes Explanation**

<table><thead><tr><th width="128">Status Code</th><th width="203">Status Name</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code></td><td>Verification Started</td><td>The KYB verification process has been initiated.</td></tr><tr><td><code>2</code></td><td>Info Submitted</td><td>The user has completed and submitted their information.</td></tr><tr><td><code>3</code></td><td>Under Review</td><td>The submitted information is being reviewed by the compliance team.</td></tr><tr><td><code>4</code></td><td>Resubmission Required</td><td>Further information or clarification is needed.</td></tr><tr><td><code>5</code></td><td>Verification Passed</td><td>The KYB verification was successful.</td></tr><tr><td><code>6</code></td><td>Verification Failed</td><td>The KYB verification was unsuccessful.</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

***

## **How to Generate an Access Token with API\_KEY** <a href="#access-token" id="access-token"></a>

To use your API\_KEY to obtain an accessToken, you will need to make a specific HTTP request. Here's how you can do it:

{% hint style="info" %}
**NOTE:** The generated accessToken is valid for **30 minutes** and will expire automatically after that.
{% endhint %}

{% tabs %}
{% tab title="Endpoint" %}

```ruby
POST https://agw.zk.me/kybpopup/api/generate-access-token
```

{% hint style="info" %}
Please remember to modify the <mark style="color:blue;">`Content-Type`</mark> in the request header to <mark style="color:blue;">`application/json`</mark>. Failing to do so might result in a <mark style="color:red;">`Parameter Error`</mark> response.
{% endhint %}
{% endtab %}

{% tab title="Request" %}

<table><thead><tr><th width="111.2421875">Name</th><th width="81.3359375">Required</th><th width="76.484375">Type</th><th>Desc</th></tr></thead><tbody><tr><td>apiKey</td><td>True</td><td>string</td><td>The API_KEY provided by zkMe.</td></tr><tr><td>appId</td><td>True</td><td>string</td><td>A unique identifier (mchNo) to DApp provided by zkMe.</td></tr></tbody></table>

{% hint style="info" %} <mark style="color:orange;">`API_KEY`</mark>can be found in [the Configuration section](https://dashboard.zk.me/integration) of the Integration on the zkMe Dashboard.
{% endhint %}
{% endtab %}

{% tab title="Response" %}

<details>

<summary><mark style="color:green;"><strong>Success</strong></mark></summary>

```json
{
    "code": 80000000,
    "data": {
        "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxxxx",
        "expiresIn": 1800
    },
    "msg": "success",
    "timestamp": 1691732474552
}
```

</details>

<details>

<summary><mark style="color:red;"><strong>Exception (AppId and API_KEY not matched)</strong></mark></summary>

```json
{
    "code": 81000014,
    "data": null,
    "msg": "AppID and API Key do not match. Access token generation failed",
    "timestamp": 1691732568774
}
```

</details>

<details>

<summary><mark style="color:red;"><strong>Exception (Parameter Error)</strong></mark></summary>

```json
{
    "code": 80000002,
    "data": null,
    "msg": "parameter error",
    "timestamp": 1691732593484
}
```

</details>
{% endtab %}
{% endtabs %}

***

## ZkMeKybWidget instance methods

<details>

<summary>launch()</summary>

Launch the zkMe KYB widget and it will be displayed in the center of your webpage.

<pre class="language-typescript"><code class="lang-typescript"><strong>launch(): void
</strong></code></pre>

</details>

<details>

<summary>on()</summary>

Listen to zkMe KYB widget events.

```typescript
on(event: 'kybFinished', callback: KybFinishedHook): void;
on(event: 'close', callback: () => void): void;
```

</details>

<details>

<summary>hide()</summary>

Hide the zkMe widget.

```typescript
hide(): void
```

</details>

<details>

<summary>destroy()</summary>

Remove the message event listener registered by the zkMe widget from the window and destroy the DOM node.

```typescript
destroy(): void
```

</details>

***
