> For the complete documentation index, see [llms.txt](https://docs.lumia.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lumia.org/build/on-chain-kyc.md).

# On-Chain KYC

This guide provides the steps and instructions for integrating Privado ID-based KYC verification directly in your frontend application, utilizing the **Privado ID verifier API** at `https://verifier-backend.privado.id`.

***

#### Prerequisites <a href="#prerequisites" id="prerequisites"></a>

Before you begin integrating Privado ID verification, ensure you have the following:

* A **React-based frontend**.
* **Frontend access** to `https://verifier-backend.privado.id` for generating QR codes and checking the verification status.
* The `qrcode.react` npm package for rendering QR codes.

***

#### Integration Steps <a href="#integration-steps" id="integration-steps"></a>

**Step 1: Set up Frontend Components**

The frontend will be responsible for interacting with users, displaying the QR code, and updating the verification status.

**1.1 React Components**

* **StatusCard**: A component that shows the current KYC status (e.g., "Pending", "Verifying", "Approved", or "Failed").
* **QRCodeSection**: Displays the QR code generated for the user to scan with their Privado ID wallet.
* **ActionButtons**: Provides buttons like "Start KYC" and "Retry" to allow users to interact with the verification process.

```javascript
// Example for displaying QR code and status
import React, { useState } from 'react';
import { handlePolygonVerification, pollVerificationStatus } from './api'; // Functions to initiate verification and poll status

const KYCPage = () => {
  const [status, setStatus] = useState('pending');
  const [qrCode, setQrCode] = useState(null);
  const [sessionID, setSessionID] = useState(null);

  const startVerification = async () => {
    const result = await handlePolygonVerification();
    setQrCode(result.qrCode);
    setSessionID(result.sessionID);
    setStatus('verifying');
    pollVerificationStatus(result.sessionID, setStatus); // Poll verification status
  };

  return (
    <div>
      <h1>Privado ID KYC Verification</h1>
      <LhStatusCard status={status} />
      {status === 'verifying' && <LhQRCodeSection qrCode={qrCode} />}
      <LhActionButtons onClick={startVerification} />
    </div>
  );
};
```

**1.2 Handle Verification Requests**

Use a function to send a **POST** request to the Privado ID API to generate the QR code.

```javascript
// Function to handle verification request
export const handlePolygonVerification = async () => {
  const response = await fetch('https://verifier-backend.privado.id/sign-in', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      chainID: "1952959480", - Lumia Testnet
      scope: [
        {
          circuitId: "credentialAtomicQueryMTPV2",
          id: 1734435086,
          query: {
            allowedIssuers: ["*"],
            context: "https://raw.githubusercontent.com/shiva-decrypt/lumai-json/main/lumiav2.jsonld",
            type: "KYC",
            credentialSubject: {
              Kyc_Approved: { "$eq": true }
            }
          }
        }
      ],
      skipClaimRevocationCheck: false
    })
  });

  const data = await response.json();
  return {
    qrCode: data.qrCode,
    sessionID: data.sessionID,
  };
};
```

**Explanation of the `body` Section in the Request**

The `body` of the request is a JSON object sent to the Privado ID verifier backend. Here's a breakdown of its components:

***

**1. `chainID: "XXXXXXX"`**

* Specifies the blockchain network used.
* `1952959480` corresponds to the Lumia Testnet.
* `994873017` corresponds to the Lumia Mainnet (Prism)

***

**2. `scope`**

* **Purpose**: Defines the query parameters and the type of credential to verify.
* Contains an array of query objects. Each query object includes:
  * `circuitId`: `"credentialAtomicQueryMTPV2"`
    * Specifies the type of cryptographic circuit used for verification.
    * In this case, it's `credentialAtomicQueryMTPV2`, which supports secure and private verification of claims.
  * `id`: `1734435086`
    * A unique identifier for the query.
  * `query`: Describes the claim or condition to be checked.
    * **`allowedIssuers`: `["*"]`**
      * Allows credentials from any issuer (`*`).
    * **`context`**:
      * A URL pointing to the JSON-LD schema defining the structure of the credential.
      * In this case, it links to a schema stored in a GitHub repository.
    * **`type`: `"KYC"`**
      * Specifies the type of credential being validated.
    * **`credentialSubject`**:
      * Defines the specific conditions the credential must meet.
      * In this example, `Kyc_Approved: { "$eq": true }` requires that the `Kyc_Approved` field in the credential is `true`.

***

**3. `skipClaimRevocationCheck: false`**

* Ensures that the claim revocation status is verified.
* If set to `true`, the verification would skip checking if the claim has been revoked, which might reduce security.

***

**Possible Modifications**

**1. Customizing Allowed Issuers**

* Instead of allowing any issuer (`allowedIssuers: ["*"]`), you can specify trusted issuers. **Example**:

  Copy

  ```
  "allowedIssuers": ["did:polygon:abc123", "did:polygon:def456"]
  ```

**2. Using a Custom Credential Type**

* Change the `type` from `"KYC"` to other credential types if needed. Ensure the schema in the `context` URL matches the new type.

**3. Dynamic `chainID` Selection**

* If your application supports multiple networks, the `chainID` can be dynamically passed based on the selected environment (e.g., mainnet or testnet).

**4. Revocation Check Skipping**

* For faster verification in non-critical use cases, set `skipClaimRevocationCheck` to `true`. However, this is not recommended for sensitive processes.

**5. Adding Additional Query Conditions**

* You can validate more fields by adding them to the `credentialSubject`. **Example**:

  Copy

  ```
  "credentialSubject": {
    "Kyc_Approved": { "$eq": true },
    "Age": { "$gte": 18 }
  }
  ```

  This ensures the user is at least 18 years old and has passed KYC.

**Step 2: Poll Verification Status**

After the QR code is generated, you need to periodically check the status of the verification to keep the user updated.

```javascript
// Function to poll verification status
export const pollVerificationStatus = async (sessionID, setStatus) => {
  const response = await fetch(`https://verifier-backend.privado.id/status?sessionID=${sessionID}`);
  const data = await response.json();

  if (data.status === 'success') {
    setStatus('approved');
  } 

  // Poll every 5 seconds until verification is completed
  if (data.status !== 'approved' && data.status !== 'failed') {
    setTimeout(() => pollVerificationStatus(sessionID, setStatus), 5000);
  }
};
```

**Step 3: Handle User Interaction**

Users can interact with the system by clicking the "Start KYC" button to initiate the verification process and retry if needed.

**Example UI Components**

```javascript
import { QRCodeSVG } from 'qrcode.react';

export const LhStatusCard = ({ status }) => {
  return (
    <div>
      <h2>Status: {status}</h2>
    </div>
  );
};

export const LhQRCodeSection = ({ qrCode }) => {
  return (
    <div>
    <QRCodeSVG
              value={qrCode}
              size={400}
              level="H"
              className="h-full w-full"
              includeMargin
              bgColor="#f3f4f6"
              fgColor="#4f46e5"
            />
    </div>
  );
};

export const LhActionButtons = ({ onClick }) => {
  return (
    <div>
      <button onClick={onClick}>Start KYC</button>
    </div>
  );
};
```

***

#### Final Steps <a href="#final-steps" id="final-steps"></a>

1. **Start the KYC Process**:
   * The user clicks the “Start KYC” button, triggering the `startVerification` function.
   * A **QR code** will be displayed for the user to scan with their Polygon ID wallet.
2. **Track the Verification Status**:
   * Once the user scans the QR code, the status will update to "Verifying."
   * The frontend will automatically poll the status every 5 seconds until the status is either "Approved" or "Failed."
3. **Handle Status Changes**:
   * Upon successful verification, the status will update to "Approved".
   * If verification fails, the user can click “Retry” to attempt the process again.

***

#### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

* **Issue**: QR code is not displayed.
  * **Solution**: Ensure that the API is returning a valid `qrCode` URL. Verify that your frontend is correctly displaying the image.
* **Issue**: Verification fails.
  * **Solution**: Confirm that the user's Privado ID wallet app is properly configured and connected to the internet.
* **Issue**: Status remains "Pending" for too long.
  * **Solution**: Ensure the sessionID is valid and being correctly used to check the verification status. You may also want to check for any issues with the Privado ID service.

***

#### Conclusion <a href="#conclusion" id="conclusion"></a>

By following this guide, you can integrate Privado ID verification directly into your frontend application, allowing users to verify their KYC status with ease. The process involves generating a QR code, tracking the status, and providing feedback to the user throughout the verification process.
