# Welcome to 0xKYC Documentation

{% hint style="info" %}
**Welcome to 0xKYC Documentation:** bellow you will find relavant pages to guide you and your team to a seamless implementation.
{% endhint %}

## Quick links

{% content-ref url="/pages/EVSfhxBastHMZ8rqPbC9" %}
[What we do](/overview/what-we-do)
{% endcontent-ref %}

{% content-ref url="/pages/4T0OmgEpxOGAcis6U9tv" %}
[Our Products](/overview/our-products)
{% endcontent-ref %}

{% content-ref url="/pages/qnCZerKcJivo3nG7Bkg2" %}
[Start Here](/developer-guides/start-here)
{% endcontent-ref %}


# What we do

{% hint style="info" %}
**What is 0xKYC?** 0xKYC is a privacy-preserving identity verification service for Web3 Gaming, Decentralized Finance and Discord​
{% endhint %}

{% embed url="<https://www.youtube.com/watch?v=QHm8tHxXlN4>" %}

## Overview

0xKYC solves the problem of duplicate accounts for web3 developers, by providing each user with biometrics-based zero-knowledge ID token​

**Privacy-Preserving**

Our clients receive a unique identifier number instead of their users’ biometric data or identity document data. This lowers the compliance burden for our clients and allows us to serve the data directly on the blockchain

**Reusable Verification**

The verification is reusable across different Web3 games, DeFi protocols and on social media (e.g. Discord servers). This creates network effects, by reducing the hurdle for end-users and creates increased incentives for new clients​

**Simplicity for Users and Clients​**

Implementation and maintenance of 0xKYC is much simpler than for a typical verification system. This allows for fast integration for clients and a smooth process for end-users to finish the verification in less than 30 seconds for the biometrics-only verification​


# Our Products

{% hint style="info" %}
Our offerin&#x67;**:** We currently have 2 main products: Sunscreen and 0xKYC. 0xKYC is our sanctions + AML check and Sunscreen is our bot detection + uniquness verification for discord
{% endhint %}

## Sunscreen - Proof of Uniqueness

Get rid of bots and users with ​multiple accounts via a frictionless biometrics scan​, we call this the "Sunscreen" check

![](https://images.unsplash.com/photo-1569144157591-c60f3f82f137?crop=entropy\&cs=tinysrgb\&fm=jpg\&ixid=MnwxOTcwMjR8MHwxfHNlYXJjaHwxfHxmZWF0dXJlfGVufDB8fHx8MTY2MDU4MzM1OQ\&ixlib=rb-1.2.1\&q=80)

## 0xKYC - Sanctions + AML

Verify whether a user is not sanctioned without revealing their name via a simple biometrics + identity document scan​, we call this the "0xKYC" check​

![](https://images.unsplash.com/photo-1555774698-0b77e0d5fac6?crop=entropy\&cs=tinysrgb\&fm=jpg\&ixid=MnwxOTcwMjR8MHwxfHNlYXJjaHwyfHxhcHB8ZW58MHx8fHwxNjYwNTgzMzQz\&ixlib=rb-1.2.1\&q=80)


# Start Here

{% hint style="info" %}
We have created a demo repository in Github for you to follow along with:

Go to mint our SBT 🚀:

* sandbox environment: [sandbox.0xkyc.id](https://sandbox.0xkyc.id/)
* production environment: [app.0xkyc.id](https://app.0xkyc.id/)
  {% endhint %}

## GETTING STARTED

## [Go to Github Tutorial](https://github.com/0xKYC/tutorial-0xkyc)

### Installation

1. Clone the tutorial repository to your local machine:

```bash
$ git clone git@github.com:0xKYC/tutorial-0xkyc.git
$ cd tutorial-0xkyc
```

2. Install the necessary packages:

```bash
$ npm install
```

### Update Configurations

3. Update **{YOUR\_PROVIDER\_URL}** to your provider url in example.ts:

```javascript
const web3 = new Web3('{YOUR_PROVIDER_URL}');
```

### Compile and Run

4. Compile the TypeScript file:

```bash
$ tsc example.ts
```

5. Execute the compiled JavaScript file:

```bash
$ node example.js
```

### Output

The output will look like below:

```
# testHasSoulScenario0
Error:  Web3 validator found 1 error[s]:
value "invalid_format" at "/0" must pass "address" validation
hasSoul: false

# testHasSoulScenario1
hasSoul: true
walletAddress: 0xb52e0c56e0A8Afc9B28c8e0a8396af3261a5e191
1. The owner is over 18.
2. The owner is not from OFAC sanctioned country.
3. The wallet address is not in the OFAC sanctioned list.

# testHasSoulScenario2
hasSoul: false
walletAddress: 0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE
- The owner has not finished 0xkyc verification process.
- Or the owner is not over 18.
- Or the owner is from OFAC sanctioned country.
- Or the wallet address is in the OFAC sanctioned list.

# testGetUUIDDataScenario0
Error:  Web3 validator found 1 error[s]:
value "invalid_format" at "/0" must pass "address" validation

# testGetUUIDDataScenario1
uuid: afb701e7-36d9-448c-9c55-ad562aba6c2e
walletAddress: 0xb52e0c56e0A8Afc9B28c8e0a8396af3261a5e191
This walletAddress has been assigned uuid by 0xkyc.

# testGetUUIDDataScenario2
uuid:
walletAddress: 0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE
This walletAddress has not been assigned uuid by 0xkyc.

# testGetUUIDDataScenario3
walletAddress: 0xb52e0c56e0A8Afc9B28c8e0a8396af3261a5e191 and walletAddress: 0x778c6Eec2b9a1Cf006e854abBcd261F63b3eb769 have the same uuid: afb701e7-36d9-448c-9c55-ad562aba6c2e
It means two addresses are owned by the same person.
NOTE: Even if the network is different, wallet addresses from the same person has the same UUID.

# testGetUUIDDataScenario4
walletAddress1: 0xb52e0c56e0A8Afc9B28c8e0a8396af3261a5e191, uuid1: afb701e7-36d9-448c-9c55-ad562aba6c2e
walletAddress2: 0xc461F7c743a428DE1F20627fbD9243bB0983C94B, uuid2: 5324d1da-c44a-47e5-857e-72db6529b440
It means two wallet addresses are owned by the different person.
```

Thank you for completing this tutorial from start to finish. 😁


# Client or Server Guide

This section focuses on a client or server side implementation. At 0xKYC we have focused on the easiest implementation experience for developers. In the following pages you can find everything you need to add a 0xKYC verification to your codebase.&#x20;


# Sunscreen - Uniquness Verification

#### Proof of Uniquness

Every user that goes through our app will be assigned a UUID, this is a unique identifier that will then be assigned and minted onto the blockchain. With every additional wallet our system picks up to be the same user, we assign the same UUID, networking individuals accross wallets. The uniquness verification system is based upon a biometric scan done of the user.


# Define ABI

#### Define the ABI

Firstly, you will need the 0xKYC contract interface, define the `ABI` in a variable below:

{% code overflow="wrap" %}

```typescript
const abi = [ { "inputs": [ { "internaltype": "string", "name": "name_", "type": "string" }, { "internaltype": "string", "name": "symbol_", "type": "string" } ], "statemutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "burn", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "mint", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internaltype": "address", "name": "previousowner", "type": "address" }, { "indexed": true, "internaltype": "address", "name": "newowner", "type": "address" } ], "name": "ownershiptransferred", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "update", "type": "event" }, { "inputs": [], "name": "_name", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "_symbol", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "_totalsbt", "outputs": [ { "internaltype": "uint256", "name": "", "type": "uint256" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "burn", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "getsbtdata", "outputs": [ { "internaltype": "uint256[2]", "name": "", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "", "type": "uint256[3]" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "hassoul", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "uint256[2]", "name": "a", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "b", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "c", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "input", "type": "uint256[3]" }, { "internaltype": "address", "name": "to", "type": "address" } ], "name": "mint", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "name", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [ { "internaltype": "address", "name": "", "type": "address" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "renounceownership", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "totalsbt", "outputs": [ { "internaltype": "uint256", "name": "", "type": "uint256" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "newowner", "type": "address" } ], "name": "transferownership", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" }, { "components": [ { "internaltype": "uint256[2]", "name": "a", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "b", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "c", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "input", "type": "uint256[3]" } ], "internaltype": "struct zksbt. Proof", "name": "_souldata", "type": "tuple" } ], "name": "updatesbt", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" }, { "internaltype": "address", "name": "verifieraddress", "type": "address" } ], "name": "validateattribute", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "view", "type": "function" } ]
```

{% endcode %}


# Get Unique Identifier of an Address

{% hint style="info" %}
A user will be assigned a UUID (Universally Unique Identifier) if they have gone done a document scan + biomentric scan (selfie) OR just a biomentric scan (motion)
{% endhint %}

To query the UUID of a wallet simply call:

```javascript
const soulbound = new web3.eth.Contract(abi, soulboundContractAddress);
const uuidData = await soulbound.methods.getUUIDData(walletAddress).call();
```

Or call our "**`GET /api/v1/uuid`**" API directly [here](https://app.gitbook.com/o/fDCD07bvM58xbmZvN3nL/s/yX8UjIeZe2T6a7dmvUvI/~/changes/9/developer-guides/public-apis#apis):

{% content-ref url="/pages/I1cb6YyupQZqjo7Rq7Ze" %}
[Public APIs](/developer-guides/public-apis)
{% endcontent-ref %}


# Working with the UUID

{% hint style="success" %}
We issue the UUID so that you can make the core decisions of what to do with duplicate individuals found afterward
{% endhint %}

### The power is in your hands

Once you have a users UUID, you can store it in an internal database and keep track of all duplicated users, as they appear. With the UUID you can then make the decision to block, warn, or allow any user, in the future or in real time!


# 0xKYC - Sanctions/ AML

Verify whether a user is not sanctioned without revealing their name via a simple biometrics + identity document scan​, we call this the "0xKYC" check​


# Contract Addresses

{% hint style="info" %}
Our product is live on Polygon Mainnet, along with Mumbai, Sepolia and Scroll testnets
{% endhint %}

### &#x20;                                                 **ENV: Production**

<table data-full-width="true"><thead><tr><th width="156" align="center">Network</th><th align="center">SBT Address</th><th align="center">Verifier Address</th><th align="center">Link</th></tr></thead><tbody><tr><td align="center">Polygon</td><td align="center"><pre data-full-width="false"><code>0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A5
</code></pre></td><td align="center"><pre><code>0xf9f1aC8E34f257a4E40d4a760891daE18Ca8A514
</code></pre></td><td align="center"><a href="https://polygonscan.com/address/0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A5">https://polygonscan.com/address/0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A5</a></td></tr><tr><td align="center">Mumbai</td><td align="center"><pre><code>0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A50xbC5ED9669fc8cA7f40e8147ff40cBf48C531eE0A
</code></pre></td><td align="center"><pre><code>0x1971f89d50E98bD426541EBcDDbd102D444C90BF
</code></pre></td><td align="center"><a href="https://mumbai.polygonscan.com/address/0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A5">https://mumbai.polygonscan.com/address/0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A5</a></td></tr><tr><td align="center">Sepolia</td><td align="center"><pre><code>0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A5
</code></pre></td><td align="center"><pre><code>0x1971f89d50E98bD426541EBcDDbd102D444C90BF
</code></pre></td><td align="center"><a href="https://sepolia.etherscan.io/address/0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A5">https://sepolia.etherscan.io/address/0x0B9119547C42e371c643BCfDFa7eeAd6C56e07A5</a></td></tr><tr><td align="center">Scroll Alpha</td><td align="center">todo</td><td align="center">todo</td><td align="center"></td></tr></tbody></table>

### &#x20;                                                   **ENV: Sandbox**

<table data-full-width="true"><thead><tr><th width="152" align="center">Network</th><th align="center">SBT Address</th><th align="center">Verifier Address</th><th align="center">Link</th></tr></thead><tbody><tr><td align="center">Mumbai</td><td align="center"><pre><code>0xbC5ED9669fc8cA7f40e8147ff40cBf48C531eE0A
</code></pre></td><td align="center"><pre><code>0xc6a1d46eD57D6eF3cb62C02e0f0002a48Ba0E022
</code></pre></td><td align="center"><a href="https://mumbai.polygonscan.com/address/0xbC5ED9669fc8cA7f40e8147ff40cBf48C531eE0A">https://mumbai.polygonscan.com/address/0xbC5ED9669fc8cA7f40e8147ff40cBf48C531eE0A</a></td></tr><tr><td align="center">Sepolia</td><td align="center"><pre><code>0xbC5ED9669fc8cA7f40e8147ff40cBf48C531eE0A
</code></pre></td><td align="center"><pre><code>0x5870f4FA295e2531bEeBb8b245DFFa13640761a4
</code></pre></td><td align="center"><a href="https://sepolia.etherscan.io/address/0xbC5ED9669fc8cA7f40e8147ff40cBf48C531eE0A">https://sepolia.etherscan.io/address/0xbC5ED9669fc8cA7f40e8147ff40cBf48C531eE0A</a></td></tr><tr><td align="center">Scroll Alpha</td><td align="center">todo</td><td align="center">todo</td><td align="center"></td></tr></tbody></table>

**Wallet address that has 0xKYC soulbound on all above networks (for testing):**

```
0xF653d75ac2f98e3e609f910A9707fd1fBAD7d1b4
```


# Define ABI

// need the new abi

#### Define the ABI

Firstly, you will need the 0xKYC contract interface, define the `ABI` in a variable below:

{% code overflow="wrap" %}

```typescript
const abi = [ { "inputs": [ { "internaltype": "string", "name": "name_", "type": "string" }, { "internaltype": "string", "name": "symbol_", "type": "string" } ], "statemutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "burn", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "mint", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internaltype": "address", "name": "previousowner", "type": "address" }, { "indexed": true, "internaltype": "address", "name": "newowner", "type": "address" } ], "name": "ownershiptransferred", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "update", "type": "event" }, { "inputs": [], "name": "_name", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "_symbol", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "_totalsbt", "outputs": [ { "internaltype": "uint256", "name": "", "type": "uint256" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "burn", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "getsbtdata", "outputs": [ { "internaltype": "uint256[2]", "name": "", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "", "type": "uint256[3]" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "hassoul", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "uint256[2]", "name": "a", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "b", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "c", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "input", "type": "uint256[3]" }, { "internaltype": "address", "name": "to", "type": "address" } ], "name": "mint", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "name", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [ { "internaltype": "address", "name": "", "type": "address" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "renounceownership", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "totalsbt", "outputs": [ { "internaltype": "uint256", "name": "", "type": "uint256" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "newowner", "type": "address" } ], "name": "transferownership", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" }, { "components": [ { "internaltype": "uint256[2]", "name": "a", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "b", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "c", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "input", "type": "uint256[3]" } ], "internaltype": "struct zksbt. Proof", "name": "_souldata", "type": "tuple" } ], "name": "updatesbt", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" }, { "internaltype": "address", "name": "verifieraddress", "type": "address" } ], "name": "validateattribute", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "view", "type": "function" } ]
```

{% endcode %}


# Checking for SBT

{% hint style="info" %}
The SBT (Soul Bound Token) will be minted if a user has gone through and scanned their ID document with the 0xKYC app.
{% endhint %}

If you want to check if a user has gone through and is verified by 0xKYC, call the method `.hasSoul()` to check a wallet for soulbound token:

```javascript
const soulbound = new web3.eth.Contract(abi, soulboundContractAddress);
const hasSoul = await soulbound.methods.hasSoul(walletAddress).call();
```

Or call our "**`GET /api/v1/hasSoul`**" API directly [here](https://app.gitbook.com/o/fDCD07bvM58xbmZvN3nL/s/yX8UjIeZe2T6a7dmvUvI/~/changes/9/developer-guides/public-apis#apis):

{% content-ref url="/pages/I1cb6YyupQZqjo7Rq7Ze" %}
[Public APIs](/developer-guides/public-apis)
{% endcontent-ref %}


# Token-gate on the Front-end

{% hint style="info" %}
Our solution is permissionless, thereby allowing for direct front-end integrations that require no permission from 0xKYC or its user base
{% endhint %}

&#x20;Here is an example of a simple front end method, token gate the key functionality of your protocol with a check for our SBT:

```javascript
    const checkSBT = async () => {
      try {
        if (address) {
          const isVerified = await checkForSBT(address);

          if (isVerified) {
            setIsAuth(true);
          } else {
            setIsAuth(false);
          }
        }
      } catch (err) {
        // handle error
      }
    };
```


# Blockchain Guide

This section focuses on a blockchain side implementation. Our system is permissionless and public on the blockchain, because of this working with 0xKYC directly contract side is also possible.


# Smart Contract

## Smart Contract Implementation (Solidity Modifier):

Here is an example of a solidity modifier that gates a core function, msg.sender must have a 0xKYC soulbound

```solidity
interface OxKYC {
    function hasSoul(address _soul) external view returns (bool);
}

contract YourContractUsingOxKYC {
    OxKYC public myOxKYC;

    constructor(address OxKYCAddress) {
        myOxKYC = OxKYC(OxKYCAddress);
    }

    modifier hasSoul {
        require(myOxKYC.hasSoul(msg.sender), "Soul does not exist");
        _;
    }

    function coreFunction() public hasSoul {
        // do something
    }
```


# On Chain Verification

{% hint style="info" %}
This on chain verification will verify the validity of the ZKP (Zero Knowledge Proof) curcuit and the underlying inputs that were used
{% endhint %}

#### JavaScript

1. Define ABI for both verifier and 0xKYC soulbound contracts:

```javascript
       
const verifierAbi = [{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"X","type":"uint256"},{"internalType":"uint256","name":"Y","type":"uint256"}],"internalType":"struct Pairing.G1Point","name":"a","type":"tuple"},{"components":[{"internalType":"uint256[2]","name":"X","type":"uint256[2]"},{"internalType":"uint256[2]","name":"Y","type":"uint256[2]"}],"internalType":"struct Pairing.G2Point","name":"b","type":"tuple"},{"components":[{"internalType":"uint256","name":"X","type":"uint256"},{"internalType":"uint256","name":"Y","type":"uint256"}],"internalType":"struct Pairing.G1Point","name":"c","type":"tuple"}],"internalType":"struct ZkVerifier.Proof","name":"proof","type":"tuple"},{"internalType":"uint256[3]","name":"input","type":"uint256[3]"}],"name":"verifyTx","outputs":[{"internalType":"bool","name":"r","type":"bool"}],"stateMutability":"view","type":"function"}]
       
       
const soulboundAbi = [ { "inputs": [ { "internaltype": "string", "name": "name_", "type": "string" }, { "internaltype": "string", "name": "symbol_", "type": "string" } ], "statemutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "burn", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "mint", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internaltype": "address", "name": "previousowner", "type": "address" }, { "indexed": true, "internaltype": "address", "name": "newowner", "type": "address" } ], "name": "ownershiptransferred", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "update", "type": "event" }, { "inputs": [], "name": "_name", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "_symbol", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "_totalsbt", "outputs": [ { "internaltype": "uint256", "name": "", "type": "uint256" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "burn", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "getsbtdata", "outputs": [ { "internaltype": "uint256[2]", "name": "", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "", "type": "uint256[3]" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" } ], "name": "hassoul", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "uint256[2]", "name": "a", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "b", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "c", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "input", "type": "uint256[3]" }, { "internaltype": "address", "name": "to", "type": "address" } ], "name": "mint", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "name", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [ { "internaltype": "address", "name": "", "type": "address" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "renounceownership", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [ { "internaltype": "string", "name": "", "type": "string" } ], "statemutability": "view", "type": "function" }, { "inputs": [], "name": "totalsbt", "outputs": [ { "internaltype": "uint256", "name": "", "type": "uint256" } ], "statemutability": "view", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "newowner", "type": "address" } ], "name": "transferownership", "outputs": [], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" }, { "components": [ { "internaltype": "uint256[2]", "name": "a", "type": "uint256[2]" }, { "internaltype": "uint256[2][2]", "name": "b", "type": "uint256[2][2]" }, { "internaltype": "uint256[2]", "name": "c", "type": "uint256[2]" }, { "internaltype": "uint256[3]", "name": "input", "type": "uint256[3]" } ], "internaltype": "struct zksbt. Proof", "name": "_souldata", "type": "tuple" } ], "name": "updatesbt", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "nonpayable", "type": "function" }, { "inputs": [ { "internaltype": "address", "name": "_soul", "type": "address" }, { "internaltype": "address", "name": "verifieraddress", "type": "address" } ], "name": "validateattribute", "outputs": [ { "internaltype": "bool", "name": "", "type": "bool" } ], "statemutability": "view", "type": "function" } ]
   
```

2. Get proof of the wallet address you want to verifiy by calling the method `.getSBTData()` within the soulbound contract and store the output into `proof` and `inputs` variables:

```javascript
 const soulbound = new web3.eth.Contract(soulboundAbi, soulboundContractAddress);
 const verifier = new web3.eth.Contract(verifierAbi, verifierContractAddress);
 const sbtData = await soulbound.methods.getSBTData(walletAddress).call();
 const proof = [sbtData[0], sbtData[1], sbtData[2]];
 const inputs = sbtData[3];
```

3. Finally call `.verifyTx()` from the verifier contract with this proof data to get the verification of the ZK:

```javascript
const isVerified = await verifier.methods.verifyTx(proof, inputs).call();
```


# No Code (Etherscan)

{% hint style="warning" %}
Please take note of the formatting, you will have to transform the output&#x20;
{% endhint %}

#### Without Code (etherscan)

1 . Find to the soulbound contract on etherscan and go to read proxy contract, paste an address you know has a soulbound into `.getSBTData` to get their zk proof, copy the response.

<figure><img src="https://camo.githubusercontent.com/0785a2338f7311563a6645be65383b4ff4c939441978908e66794aa22d7951f9/68747470733a2f2f696d6167652d686f7374696e672d30786b79632e73332e616d617a6f6e6177732e636f6d2f53637265656e73686f742b323032332d30312d32332b61742b31322e33302e35312e706e67" alt=""><figcaption></figcaption></figure>

2. Then find the verifier contract on etherscan and paste this proof to check if users proof is valid!

<figure><img src="https://camo.githubusercontent.com/1a29478be869cd78be0133289006429576cdd5aca30bfa7a76cc34431cb309f2/68747470733a2f2f696d6167652d686f7374696e672d30786b79632e73332e616d617a6f6e6177732e636f6d2f53637265656e73686f742b323032332d30312d32332b61742b31322e33382e34322e706e67" alt=""><figcaption></figcaption></figure>

**Please format for etherscan as per this example:**

Proof (tuple):

```
[  [ '8710537528348043357141709201819101354012824719334955420250292216392076623899' , '3924814251382815765284288191214228856632341894768555820344089160680175670834' ] , [ ['5911471759468079394754875175555908512976069771244464522376191264634565769159' , '21803559666175154912563263357159215640811846710703142497379156859129992688708' ] , ['16372078897919258359127917458154316186434995490375203292632038714576109276118' , '14927880659458573269668996342982593168700277969593660033945567575570075927076' ] ], [ '5645922302702090731612994530752097236431737049422847898087930472517022681634', '738883248833279286489328916624252544304195866700567499279266109075055540821' ] ]
```

input (uint256):

```
[18,0,1]
```


# Public APIs

This section focuses on a API implementation. We would like to allow for all developers to be able to integrate, even beyond the scope of web3.

## Links

* sandbox: <https://sandboxapi.0xkyc.id/docs>

{% hint style="info" %}
You can use already configured test account.

apiKey: "test1"

apiSecret: "123456789123456789"
{% endhint %}

* prod: [https://api.0xkyc.id/docs](https://sandboxapi.0xkyc.id/docs)

{% hint style="info" %}
You need to get issued an apiKey from us.

Please send an email to us <Support@0xkyc.id> using the *<mark style="color:orange;">**apiKey request form**</mark>* below after changing #{something} to the proper one.
{% endhint %}

<details>

<summary><em><mark style="color:orange;"><strong>apiKey request form</strong></mark></em></summary>

Email Title

```
[ApiKey Request] from #{yourName or organizationName}
```

Email Content

```
Dear 0xkyc Support Team,
I am writing to request an API key for accessing the services offered by 0xkyc.

Details:
Name/Organization: #{yourName or organizationName}
Purpose of Integration: #{Briefly describe why you want to integrate with 0xkyc, such as "We are developing a financial app that requires KYC checks for our users."}

Contact Information:
Email: #{yourEmail}
(optional)Website: #{yourWebsiteLink}
```

</details>

## APIs

{% openapi src="/files/Elv8SurbXEpL5aTeju7E" path="/auth" method="post" %}
[openedApiDocs.json](https://3963575259-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyX8UjIeZe2T6a7dmvUvI%2Fuploads%2FI2cukrgzuiD8jqRkDgVL%2FopenedApiDocs.json?alt=media\&token=d30c292e-74f7-4b06-aa7d-57a5a5fc520e)
{% endopenapi %}

{% openapi src="/files/Elv8SurbXEpL5aTeju7E" path="/api/v1/hasSoul" method="get" %}
[openedApiDocs.json](https://3963575259-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyX8UjIeZe2T6a7dmvUvI%2Fuploads%2FI2cukrgzuiD8jqRkDgVL%2FopenedApiDocs.json?alt=media\&token=d30c292e-74f7-4b06-aa7d-57a5a5fc520e)
{% endopenapi %}

{% openapi src="/files/Elv8SurbXEpL5aTeju7E" path="/api/v1/uuid" method="get" %}
[openedApiDocs.json](https://3963575259-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyX8UjIeZe2T6a7dmvUvI%2Fuploads%2FI2cukrgzuiD8jqRkDgVL%2FopenedApiDocs.json?alt=media\&token=d30c292e-74f7-4b06-aa7d-57a5a5fc520e)
{% endopenapi %}

{% openapi src="/files/Elv8SurbXEpL5aTeju7E" path="/api/v1/pairs" method="get" %}
[openedApiDocs.json](https://3963575259-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyX8UjIeZe2T6a7dmvUvI%2Fuploads%2FI2cukrgzuiD8jqRkDgVL%2FopenedApiDocs.json?alt=media\&token=d30c292e-74f7-4b06-aa7d-57a5a5fc520e)
{% endopenapi %}


