Identity verification
Configure the identity verification compliance module to require verified OnchainID claims for all asset transfers. Build logical expressions combining multiple claim requirements.
The identity verification compliance module requires OnchainID claim topics before regulated asset operations can complete. Pass the module address and a postfix claim expression in initialModulePairs during asset creation.

For the full module reference, including the runtime flow, trusted issuer path, failure modes, and expression semantics, see Identity Verification reference. For the underlying wallet, OnchainID, claim-topic, and trusted issuer model, see Claims and identity. For the web interface approach, see the compliance overview.
Prerequisites
You need a Platform URL (for example https://your-platform.example.com) and an API key from a user with the Token Manager role. See Getting Started for API key setup.
You also need a token factory for your desired asset type deployed to the network, and a wallet verification method enabled on your account (pincode or 2FA).
How identity verification works
Integrators and auditors both need to understand this gate. When you add this module, the blockchain validates every transfer by checking the recipient's OnchainID claims against the token's configured postfix expression. A claim counts only when the topic exists, the recipient wallet resolves to an accepted identity, the wallet is not marked as lost, and a trusted issuer validates the claim signature and data.
- Recipient check: The receiving wallet must resolve to an accepted OnchainID that is not marked as lost.
- Claim check: That OnchainID must hold a valid claim for every topic the expression requires.
- Trusted issuer: A registered claim signer in the asset's issuer registry must have signed each claim.
The module evaluates the recipient only. It does not check the sender. If the expression evaluates to false, the transfer reverts with RecipientNotVerified before execution.
Configuration parameters
Pass these parameters when you attach the compliance module during asset creation. All three fields are required.
| Parameter | Type | Description |
|---|---|---|
typeId | string | Must be "identity-verification" |
module | string | Identity verification module contract address (from system query) |
values | array | Postfix expression nodes defining the required claim logic |
Expression nodes
The values array contains postfix expression nodes that define which claims the module requires. Each node has two fields to configure:
| 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" |
The expression can contain up to 32 nodes. A non-empty expression must leave exactly one boolean value on the stack after evaluation. Topic ID 0 is invalid. An empty expression skips claim-topic evaluation, but the recipient wallet still needs a registered identity and must not be marked as lost.
Configuring identity verification during asset creation
Get the module address
Query the system to retrieve the registered module address. You need this address for the initialModulePairs payload in step 3.
curl -X GET "https://your-platform.example.com/api/system/default" \
-H "X-Api-Key: YOUR_API_KEY"Response:
{
"complianceModuleRegistry": {
"complianceModules": [
{
"typeId": "identity-verification",
"module": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
"name": "Identity Verification Module"
}
// ... other modules
]
}
}Copy the module address for the typeId: "identity-verification" entry. You will pass it in step 3.
Choose claim topics
Select the topics you want to enforce. The platform computes each topic ID as keccak256(topicName). Record the ID for every claim type you plan to require.
The tables below group topics by context. Collect the IDs for all claims your asset requires.
Investor-level claims apply to the wallets transacting with the asset.
| Topic | Topic ID (BigInt) |
|---|---|
knowYourCustomer | 26984799302505749158794800959285050858086405868089409909048783980951278841746 |
antiMoneyLaundering | 66602700950116947137359654609674923607788815289970476259958745144319039408766 |
qualifiedInstitutionalInvestor | 39526553109170329799339511574661256630735485618560740361645615581310848276505 |
professionalInvestor | 82180795564044264154236077867753775185787185513502198122023755895636360079450 |
accreditedInvestor | 15733030998618876990024220391915773205162379317494393310546829862321881862123 |
accreditedInvestorVerified | 59850607985445873266538496619638148123529590973767384129725397368921421733377 |
regulationS | 110498984792486559366779193967170177172527553783122289566437277521370918941833 |
Issuer-level claims capture regulatory standing for the token issuer. Use these when the asset's rules require the issuing entity to hold specific licenses or filings.
| Topic | Topic ID (BigInt) |
|---|---|
issuerProspectusFiled | 66024707054635888688268119510009865452443315877106845614779928773130009296293 |
issuerProspectusExempt | 108155241138976356337931447616840292633551902984574900198960811245767215772826 |
issuerLicensed | 4159646717597184831767716799371953881543937679636133282035549426319534456864 |
issuerReportingCompliant | 63974049055435959798075765549996859356159125666706735332156257908409531829710 |
issuerJurisdiction | 22945659622044541592208660721714212954694094425401272022345597464077438219436 |
Asset-level claims describe attributes of the regulated asset itself. Attach these when the asset's on-chain record must carry provenance, pricing, or classification data.
| Topic | Topic ID (BigInt) |
|---|---|
collateral | 56591694316807385155654796962642700009023257328234168678289712861780104020528 |
uniqueIdentifier | 114741468009595078276449793420639789199829227967433767091939592755701866581418 |
assetClassification | 24450086974696203741514129497527543680077858637075869492686262873957363087146 |
basePrice | 57654513796690178928725925529203455242162418455779606444866766669020006213509 |
assetIssuer | 59193974906477606357781697605998854609236670153591542535032894715512537823578 |
assetLocation | 8432405482680553454773023573904831382358253771058496665012951440405906006611 |
General claims apply across participant and asset contexts. They cover generic identity markers and custom extensions that do not fit the other categories.
| Topic | Topic ID (BigInt) |
|---|---|
contractIdentity | 43841672744129833047570617593608746101743408532017342577134968204499777399068 |
custom | 4204500278131556441620930517354114011833808539324421779944429921463295225973 |
Create the asset with identity verification
Include the module in the initialModulePairs array when creating your asset. The example below creates an equity asset that requires the knowYourCustomer claim on every transfer.
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:
{
"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 (including identity, accessControl, complianceModuleConfigs, userPermissions, and stats). The asset starts paused by default.
The table below lists the key fields, each mapping to the initialModulePairs entry structure in the Request parameters section.
| Field | Description |
|---|---|
typeId | Must be "identity-verification" for this module |
module | The identity verification module address from step 1 |
values | Array of postfix 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 |
Confirm the configuration
Query the token to verify the platform activated the module. The complianceModuleConfigs array lists every active compliance module for that token.
curl -X GET "https://your-platform.example.com/api/token/0x1234567890AbCdEf1234567890AbCdEf12345678" \
-H "X-Api-Key: YOUR_API_KEY"Response (relevant fields):
{
"id": "0x1234567890AbCdEf1234567890AbCdEf12345678",
"type": "equity",
"name": "KYC Protected Equity",
"symbol": "KYCE",
"complianceModuleConfigs": [
{
"complianceModule": {
"typeId": "identity-verification",
"module": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F"
}
}
]
}Check that complianceModuleConfigs contains an entry with typeId: "identity-verification". Once confirmed, the module is active and the asset enforces identity verification on every transfer.
Expression examples
The examples below show how to construct the values array for common compliance scenarios. Each example demonstrates one pattern; combine them as your asset's regulatory requirements demand. For the full expression semantics, operator precedence, and node type reference, see the Identity Verification reference.
Single requirement (KYC only)
For most regulated assets, a single KYC check is sufficient. The values array contains one TOPIC node. The recipient wallet must hold a valid knowYourCustomer claim from a trusted issuer.
{
"values": [
{
"nodeType": 0,
"value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
}
]
}KYC and AML combined
Use an AND node to require both knowYourCustomer and antiMoneyLaundering. List the first TOPIC node, then the AND operator node, then the second TOPIC node:
{
"values": [
{
"nodeType": 0,
"value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
},
{ "nodeType": 1, "value": "0" },
{
"nodeType": 0,
"value": "66602700950116947137359654609674923607788815289970476259958745144319039408766"
}
]
}Alternative requirements (KYC OR accreditedInvestor)
Use an OR node to accept either knowYourCustomer or accreditedInvestor. This pattern suits assets where different investor types qualify under different rules:
{
"values": [
{
"nodeType": 0,
"value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
},
{ "nodeType": 2, "value": "0" },
{
"nodeType": 0,
"value": "15733030998618876990024220391915773205162379317494393310546829862321881862123"
}
]
}Complex expression with grouping
Use grouping to require (KYC AND AML) OR qualifiedInstitutionalInvestor. Add the literal strings "(" and ")" as array elements around the sub-expression:
{
"values": [
{
"nodeType": 0,
"value": "26984799302505749158794800959285050858086405868089409909048783980951278841746"
},
{ "nodeType": 1, "value": "0" },
{
"nodeType": 0,
"value": "66602700950116947137359654609674923607788815289970476259958745144319039408766"
},
{ "nodeType": 2, "value": "0" },
{
"nodeType": 0,
"value": "39526553109170329799339511574661256630735485618560740361645615581310848276505"
}
]
}Request parameters
Use these fields when constructing the module configuration. The values array drives on-chain evaluation, so every node must be valid before you submit the request.
Identity verification module configuration
Fields for the identity verification entry in initialModulePairs. The values field accepts node objects and "(" / ")" grouping markers.
| Parameter | Type | Required | Description |
|---|---|---|---|
typeId | string | Yes | Must be "identity-verification" |
module | string | Yes | Module contract address, retrieved from the system query |
values | array | Yes | Postfix expression array containing topic nodes, operator nodes, and optional grouping markers |
values[] | object or string | Yes | Use an expression node object, or the literal strings "(" and ")" for grouping |
values[].nodeType | number | For node objects | 0 = TOPIC, 1 = AND, 2 = OR, 3 = NOT |
values[].value | string | For node objects | Topic ID for TOPIC nodes, "0" for operators |
Wallet verification object
Include a wallet verification object in every mutation request to authorize the on-chain write. The secretVerificationCode must match your configured method: a 6-digit code for PINCODE, a backup code for SECRET_CODES, or a TOTP for OTP.
| Field | Type | Description |
|---|---|---|
secretVerificationCode | string | 6-digit pincode or TOTP code |
verificationType | string | "PINCODE" (default), "SECRET_CODES", or "OTP" |
If you omit verificationType, the platform defaults to "PINCODE". Use "OTP" for TOTP-based authenticators, or "SECRET_CODES" for backup code authentication.
Best practices
Claim selection
Choose claims that match your regulatory context. Start with knowYourCustomer for basic compliance, then layer additional claims as your rules require. The combination determines the strictness of the gate for every transfer on that asset.
Add antiMoneyLaundering for enhanced due diligence. Use accreditedInvestor or qualifiedInstitutionalInvestor for securities with investor restrictions. Combine claims with AND for stricter requirements, or with OR for flexibility.
Expression design
Keep expressions simple: a single topic is sufficient in most cases. Test complex expressions in a non-production environment and document the logic for compliance audits. Use OR with accreditation claims to support different investor types.
Trusted issuers
- Confirm all claim issuers appear in the trusted issuer registry before enabling the module.
- Verify each issuer's credentials before adding them.
- Review issuer permissions on a regular schedule.
Troubleshooting
Use the table below to identify the cause and corrective step for each error.
| 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 | Check that every operator has the required operand, that parentheses balance, and that each node uses a valid nodeType |
Invalid topic ID | Verify topic ID matches the keccak256 hash of the claim topic name |
RecipientNotVerified | The expression evaluated to false for the recipient. Check identity registration, claims, topic IDs, and trusted issuer registrations. See the Identity Verification reference for the full failure mode matrix. |
Related guides
- Identity Verification reference - Runtime claim evaluation, trusted issuer lookup, failure behavior, and expression semantics
- Verify KYC - Issue KYC verifications to users
- Configure Trusted Issuers - Set up issuer permissions