# Smart identity verification

Source: https://docs.settlemint.com/docs/developer-guides/compliance/smart-identity-verification
Configure the identity verification compliance module to require verified OnchainID
claims for all asset transfers. Build logical expressions combining multiple claim requirements.




This guide explains how to configure the identity verification compliance module when creating an asset via API. This module ensures both sender and recipient wallets have verified OnchainID claims before any transfer can occur.

![On-chain identity registry for market participants](/docs/screenshots/identity/onchain-identity.webp)

For the web interface approach, see the [compliance overview](/docs/user-guides/compliance/overview).

## Prerequisites [#prerequisites]

* Platform URL (e.g., `https://your-platform.example.com`)
* API key from a user with the **Token Manager** role (see [Getting Started](/docs/developer-guides/api-integration/getting-started) for API key setup)
* Token factory for your desired asset type must be deployed
* Wallet verification method enabled on your account (pincode or 2FA)

## How identity verification works [#how-identity-verification-works]

When you enable the identity verification compliance module on an asset, the blockchain validates every transfer by checking:

1. **Sender verification** - The sending wallet must have an OnchainID with the required claim(s)
2. **Recipient verification** - The receiving wallet must have an OnchainID with the required claim(s)
3. **Trusted issuer** - The claim must be issued by an issuer in the asset's trusted issuer registry

If any check fails, the transfer is rejected on-chain.

<Callout type="info" title="Minting is also validated">
  When minting new units, the recipient wallet must also pass identity verification. Only wallets with valid claims can
  receive newly minted assets.
</Callout>

## Configuration parameters [#configuration-parameters]

When configuring the identity verification module during asset creation, you set these parameters:

| Parameter | Type   | Description                                                       |
| --------- | ------ | ----------------------------------------------------------------- |
| `typeId`  | string | Must be `"identity-verification"`                                 |
| `module`  | string | Identity verification module contract address (from system query) |
| `values`  | array  | Expression nodes defining the required claim logic                |

### Expression nodes [#expression-nodes]

The `values` array contains expression nodes that define which claims are required. Each node has two fields:

| Field      | Type   | Description                                                        |
| ---------- | ------ | ------------------------------------------------------------------ |
| `nodeType` | number | Operation type: `0` = TOPIC, `1` = AND, `2` = OR, `3` = NOT        |
| `value`    | string | For TOPIC nodes: the claim topic ID (BigInt). For operators: `"0"` |

<Callout type="info" title="Understanding expressions">
  Expressions use **infix notation** in the API - topics and operators are listed in reading order. For example, "KYC
  AND AML" is expressed as: `[KYC_TOPIC, AML_TOPIC, AND_OPERATOR]`. The system converts this to postfix notation for
  on-chain evaluation.
</Callout>

## Configuring identity verification during asset creation [#configuring-identity-verification-during-asset-creation]

<Steps>
  <Step>
    ### Get identity verification module address [#get-identity-verification-module-address]

    Query the system to get the registered identity verification compliance module address:

    ```bash
    curl -X GET "https://your-platform.example.com/api/system/default" \
      -H "X-Api-Key: YOUR_API_KEY"
    ```

    **Response:**

    ```json
    {
      "complianceModuleRegistry": {
        "complianceModules": [
          {
            "typeId": "identity-verification",
            "module": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
            "name": "SMART Identity Verification Module"
          }
          // ... other modules
        ]
      }
    }
    ```

    Save the `module` address for the `typeId: "identity-verification"` entry.
  </Step>

  <Step>
    ### Choose claim topic IDs [#choose-claim-topic-ids]

    Select the claim topics you want to require. Each topic has a unique ID computed as `keccak256(topicName)`:

    **Investor-level claims:**

    | Topic                            | Topic ID (BigInt)                                                                |
    | -------------------------------- | -------------------------------------------------------------------------------- |
    | `knowYourCustomer`               | `26984799302505749158794800959285050858086405868089409909048783980951278841746`  |
    | `antiMoneyLaundering`            | `66602700950116947137359654609674923607788815289970476259958745144319039408766`  |
    | `qualifiedInstitutionalInvestor` | `39526553109170329799339511574661256630735485618560740361645615581310848276505`  |
    | `professionalInvestor`           | `82180795564044264154236077867753775185787185513502198122023755895636360079450`  |
    | `accreditedInvestor`             | `15733030998618876990024220391915773205162379317494393310546829862321881862123`  |
    | `accreditedInvestorVerified`     | `59850607985445873266538496619638148123529590973767384129725397368921421733377`  |
    | `regulationS`                    | `110498984792486559366779193967170177172527553783122289566437277521370918941833` |

    **Issuer-level claims:**

    | Topic                      | Topic ID (BigInt)                                                                |
    | -------------------------- | -------------------------------------------------------------------------------- |
    | `issuerProspectusFiled`    | `66024707054635888688268119510009865452443315877106845614779928773130009296293`  |
    | `issuerProspectusExempt`   | `108155241138976356337931447616840292633551902984574900198960811245767215772826` |
    | `issuerLicensed`           | `4159646717597184831767716799371953881543937679636133282035549426319534456864`   |
    | `issuerReportingCompliant` | `63974049055435959798075765549996859356159125666706735332156257908409531829710`  |
    | `issuerJurisdiction`       | `22945659622044541592208660721714212954694094425401272022345597464077438219436`  |

    **Asset-level claims:**

    | Topic                 | Topic ID (BigInt)                                                                |
    | --------------------- | -------------------------------------------------------------------------------- |
    | `collateral`          | `56591694316807385155654796962642700009023257328234168678289712861780104020528`  |
    | `uniqueIdentifier`    | `114741468009595078276449793420639789199829227967433767091939592755701866581418` |
    | `assetClassification` | `24450086974696203741514129497527543680077858637075869492686262873957363087146`  |
    | `basePrice`           | `57654513796690178928725925529203455242162418455779606444866766669020006213509`  |
    | `assetIssuer`         | `59193974906477606357781697605998854609236670153591542535032894715512537823578`  |
    | `assetLocation`       | `8432405482680553454773023573904831382358253771058496665012951440405906006611`   |

    **General claims:**

    | Topic              | Topic ID (BigInt)                                                               |
    | ------------------ | ------------------------------------------------------------------------------- |
    | `contractIdentity` | `43841672744129833047570617593608746101743408532017342577134968204499777399068` |
    | `custom`           | `4204500278131556441620930517354114011833808539324421779944429921463295225973`  |
  </Step>

  <Step>
    ### Create asset with identity verification module [#create-asset-with-identity-verification-module]

    Include the identity verification module in the `initialModulePairs` array when creating your asset.

    **Example: Require KYC verification**

    ```bash
    curl -X POST "https://your-platform.example.com/api/token/create" \
      -H "X-Api-Key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "type": "equity",
        "name": "KYC Protected Equity",
        "symbol": "KYCE",
        "decimals": 18,
        "countryCode": 840,
        "priceCurrency": "USD",
        "basePrice": "100",
        "initialModulePairs": [
          {
            "typeId": "identity-verification",
            "module": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
            "values": [
              {
                "nodeType": 0,
                "value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
              }
            ]
          }
        ],
        "walletVerification": {
          "secretVerificationCode": "YOUR_PINCODE",
          "verificationType": "PINCODE"
        }
      }'
    ```

    **Response:**

    ```json
    {
      "id": "0x1234567890AbCdEf1234567890AbCdEf12345678",
      "type": "equity",
      "createdAt": "2025-01-15T10:30:00.000Z",
      "name": "KYC Protected Equity",
      "symbol": "KYCE",
      "decimals": 18,
      "basePrice": "[\"100\",0]",
      "basePriceCurrencyCode": "USD",
      "totalSupply": "[\"0\",0]",
      "pausable": {
        "paused": true
      }
    }
    ```

    The response includes the full asset object with additional fields like `identity`, `accessControl`, `complianceModuleConfigs`, `userPermissions`, and `stats`. Note that the asset starts paused by default.

    **Key fields in `initialModulePairs`:**

    | Field               | Description                                                |
    | ------------------- | ---------------------------------------------------------- |
    | `typeId`            | Must be `"identity-verification"` for this module          |
    | `module`            | The identity verification module address from step 1       |
    | `values`            | Array of expression nodes defining required claims         |
    | `values[].nodeType` | `0` for claim topics, `1` for AND, `2` for OR, `3` for NOT |
    | `values[].value`    | Topic ID (BigInt string) for topics, `"0"` for operators   |
  </Step>

  <Step>
    ### Verify configuration [#verify-configuration]

    Query the asset to confirm the identity verification module is configured:

    ```bash
    curl -X GET "https://your-platform.example.com/api/token/0x1234567890AbCdEf1234567890AbCdEf12345678" \
      -H "X-Api-Key: YOUR_API_KEY"
    ```

    **Response (relevant fields):**

    ```json
    {
      "id": "0x1234567890AbCdEf1234567890AbCdEf12345678",
      "type": "equity",
      "name": "KYC Protected Equity",
      "symbol": "KYCE",
      "complianceModuleConfigs": [
        {
          "complianceModule": {
            "typeId": "identity-verification",
            "module": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F"
          }
        }
      ]
    }
    ```

    Confirm that `complianceModuleConfigs` contains an entry with `typeId: "identity-verification"`.
  </Step>
</Steps>

## Expression examples [#expression-examples]

### Single requirement (KYC only) [#single-requirement-kyc-only]

Require only the `knowYourCustomer` claim:

```json
{
  "values": [
    {
      "nodeType": 0,
      "value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
    }
  ]
}
```

### Combined requirements (KYC AND AML) [#combined-requirements-kyc-and-aml]

Require both `knowYourCustomer` AND `antiMoneyLaundering` claims:

```json
{
  "values": [
    {
      "nodeType": 0,
      "value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
    },
    {
      "nodeType": 0,
      "value": "66602700950116947137359654609674923607788815289970476259958745144319039408766"
    },
    { "nodeType": 1, "value": "0" }
  ]
}
```

### Alternative requirements (KYC OR accreditedInvestor) [#alternative-requirements-kyc-or-accreditedinvestor]

Require either `knowYourCustomer` OR `accreditedInvestor` claim:

```json
{
  "values": [
    {
      "nodeType": 0,
      "value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
    },
    {
      "nodeType": 0,
      "value": "15733030998618876990024220391915773205162379317494393310546829862321881862123"
    },
    { "nodeType": 2, "value": "0" }
  ]
}
```

### Complex expression with grouping [#complex-expression-with-grouping]

Require `(KYC AND AML) OR qualifiedInstitutionalInvestor`:

```json
{
  "values": [
    "(",
    {
      "nodeType": 0,
      "value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
    },
    {
      "nodeType": 0,
      "value": "66602700950116947137359654609674923607788815289970476259958745144319039408766"
    },
    { "nodeType": 1, "value": "0" },
    ")",
    {
      "nodeType": 0,
      "value": "39526553109170329799339511574661256630735485618560740361645615581310848276505"
    },
    { "nodeType": 2, "value": "0" }
  ]
}
```

<Callout type="info" title="Operator precedence">
  When building expressions without parentheses, operators follow this precedence (highest to lowest): NOT (3) → AND (2)
  → OR (1). Use parentheses `"("` and `")"` as array elements to explicitly group operations.
</Callout>

## Request parameters [#request-parameters]

### Identity verification module configuration [#identity-verification-module-configuration]

| Parameter           | Type   | Required | Description                                                       |
| ------------------- | ------ | -------- | ----------------------------------------------------------------- |
| `typeId`            | string | Yes      | Must be `"identity-verification"`                                 |
| `module`            | string | Yes      | Module contract address (from system query)                       |
| `values`            | array  | Yes      | Expression nodes array (topics, operators, and optional grouping) |
| `values[].nodeType` | number | Yes      | `0` = TOPIC, `1` = AND, `2` = OR, `3` = NOT                       |
| `values[].value`    | string | Yes      | Topic ID for TOPIC nodes, `"0"` for operators                     |

### Wallet verification object [#wallet-verification-object]

| Field                    | Type   | Description                                         |
| ------------------------ | ------ | --------------------------------------------------- |
| `secretVerificationCode` | string | 6-digit pincode or TOTP code                        |
| `verificationType`       | string | `"PINCODE"` (default), `"SECRET_CODES"`, or `"OTP"` |

## Best practices [#best-practices]

### Claim selection [#claim-selection]

* Start with `knowYourCustomer` for basic regulatory compliance
* Add `antiMoneyLaundering` for enhanced due diligence requirements
* Use `accreditedInvestor` or `qualifiedInstitutionalInvestor` for securities with investor restrictions
* Combine claims with AND for stricter requirements, OR for flexibility

### Expression design [#expression-design]

* Keep expressions simple when possible - a single topic is often sufficient
* Test complex expressions thoroughly before deploying to production
* Document your expression logic for compliance audits
* Consider using OR with accreditation claims to support different investor types

### Trusted issuers [#trusted-issuers]

* Ensure claim issuers are registered in the trusted issuer registry
* Verify issuer credentials before adding them to the registry
* Regularly audit trusted issuer permissions

## Troubleshooting [#troubleshooting]

| Issue                     | Solution                                                                     |
| ------------------------- | ---------------------------------------------------------------------------- |
| `401 Unauthorized`        | API key is invalid, expired, or disabled                                     |
| `403 USER_NOT_AUTHORIZED` | Ensure your account has `tokenManager` role                                  |
| `Module not found`        | Query `/system/default` to get the correct module address                    |
| `Invalid expression`      | Verify expression nodes follow the correct format with valid nodeType values |
| `Invalid topic ID`        | Verify topic ID matches the keccak256 hash of the claim topic name           |

## Related guides [#related-guides]

* [Verify KYC](/docs/developer-guides/compliance/verify-kyc) - Issue KYC verifications to users
* [Configure Trusted Issuers](/docs/developer-guides/compliance/configure-trusted-issuers) - Set up issuer permissions
