Overview
Activate a minted identity to make it soulbound (non-transferable). Once activated, the identity becomes permanently bound to the owner’s wallet and can be used as a parameter across all ZKScore APIs. Activation is irreversible.
Activation is permanent! Once an identity is activated, it cannot be transferred or deactivated. Make sure you’re activating the correct identity.
Request Body
The NFT token ID of the identity to activate (obtained from minting)
Cryptographic signature from the identity owner proving ownership
The wallet address of the identity owner (must match the minted identity)
Response
Indicates if the activation was successful
The wallet address that owns this identity
Whether the identity is activated (always true after successful activation)
ISO 8601 timestamp of when the identity was activated
The blockchain transaction hash for the activation
Examples
curl -X POST https://api.onzks.com/v1/identity/activate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tokenId": 12345,
"signature": "0xabc123...",
"walletAddress": "0x742d35Cc6635C0532925a3b844D1FF4e1321"
}'
Response Example
{
"success" : true ,
"identity" : {
"tokenId" : 12345 ,
"name" : "alice" ,
"ownerAddress" : "0x742d35cc6635c0532925a3b844d1ff4e1321" ,
"isActivated" : true ,
"activatedAt" : "2024-01-15T11:00:00Z" ,
"transactionHash" : "0xdef456..."
}
}
Error Responses
404 Not Found
400 Bad Request - Already Activated
401 Unauthorized - Invalid Signature
403 Forbidden - Not Owner
{
"success" : false ,
"error" : "IDENTITY_NOT_FOUND" ,
"message" : "Identity with tokenId 12345 not found"
}
Signature Generation
Using ethers.js
import { ethers } from 'ethers' ;
async function generateActivationSignature ( tokenId , privateKey ) {
const signer = new ethers . Wallet ( privateKey );
const message = `Activate identity ${ tokenId } ` ;
const signature = await signer . signMessage ( message );
return {
signature ,
walletAddress: signer . address
};
}
// Usage
const { signature , walletAddress } = await generateActivationSignature ( 12345 , privateKey );
Using web3.js
import Web3 from 'web3' ;
async function generateActivationSignature ( tokenId , privateKey ) {
const web3 = new Web3 ();
const account = web3 . eth . accounts . privateKeyToAccount ( privateKey );
const message = `Activate identity ${ tokenId } ` ;
const signature = await account . sign ( message );
return {
signature: signature . signature ,
walletAddress: account . address
};
}
async function generateActivationSignature ( tokenId ) {
if ( ! window . ethereum ) {
throw new Error ( 'MetaMask not installed' );
}
const accounts = await window . ethereum . request ({
method: 'eth_requestAccounts'
});
const walletAddress = accounts [ 0 ];
const message = `Activate identity ${ tokenId } ` ;
const signature = await window . ethereum . request ({
method: 'personal_sign' ,
params: [ message , walletAddress ]
});
return { signature , walletAddress };
}
Use Cases
1. Complete Onboarding Flow
Mint and activate an identity in sequence:
async function completeOnboarding ( name , walletAddress , privateKey ) {
// Step 1: Mint identity
const mintResponse = await fetch ( 'https://api.onzks.com/v1/identity/mint' , {
method: 'POST' ,
headers: {
'Authorization' : 'Bearer YOUR_API_KEY' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({ name , walletAddress })
});
const { identity } = await mintResponse . json ();
console . log ( `Identity minted: ${ identity . name } .zks` );
// Step 2: Generate signature
const signer = new ethers . Wallet ( privateKey );
const message = `Activate identity ${ identity . tokenId } ` ;
const signature = await signer . signMessage ( message );
// Step 3: Activate identity
const activateResponse = await fetch ( 'https://api.onzks.com/v1/identity/activate' , {
method: 'POST' ,
headers: {
'Authorization' : 'Bearer YOUR_API_KEY' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
tokenId: identity . tokenId ,
signature ,
walletAddress
})
});
const { identity : activatedIdentity } = await activateResponse . json ();
console . log ( `Identity activated: ${ activatedIdentity . name } .zks` );
return activatedIdentity ;
}
2. Activation with User Confirmation
Request user confirmation before activation:
async function activateWithConfirmation ( tokenId ) {
const confirmed = await showConfirmationDialog (
'Activate Identity' ,
'This action is permanent and cannot be undone. Continue?'
);
if ( ! confirmed ) {
return null ;
}
const { signature , walletAddress } = await generateActivationSignature ( tokenId );
const response = await fetch ( 'https://api.onzks.com/v1/identity/activate' , {
method: 'POST' ,
headers: {
'Authorization' : 'Bearer YOUR_API_KEY' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({ tokenId , signature , walletAddress })
});
return response . json ();
}
3. Batch Activation
Activate multiple identities:
async function batchActivate ( identities , privateKey ) {
const signer = new ethers . Wallet ( privateKey );
const results = [];
for ( const identity of identities ) {
try {
const message = `Activate identity ${ identity . tokenId } ` ;
const signature = await signer . signMessage ( message );
const response = await fetch ( 'https://api.onzks.com/v1/identity/activate' , {
method: 'POST' ,
headers: {
'Authorization' : 'Bearer YOUR_API_KEY' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
tokenId: identity . tokenId ,
signature ,
walletAddress: signer . address
})
});
const result = await response . json ();
results . push ({ success: true , identity: result . identity });
// Rate limiting
await new Promise ( resolve => setTimeout ( resolve , 1000 ));
} catch ( error ) {
results . push ({ success: false , tokenId: identity . tokenId , error });
}
}
return results ;
}
Best Practices
1. Verify Before Activation
Check identity details before activating:
// Get identity details
const identity = await getIdentity ( tokenId );
// Verify it's the correct identity
console . log ( `About to activate: ${ identity . name } .zks` );
console . log ( `Owner: ${ identity . ownerAddress } ` );
// Confirm with user
const confirmed = confirm ( 'Activate this identity?' );
if ( confirmed ) {
await activateIdentity ( tokenId );
}
2. Handle Errors Gracefully
Provide clear error messages:
try {
await activateIdentity ( tokenId );
} catch ( error ) {
if ( error . code === 'ALREADY_ACTIVATED' ) {
console . log ( 'Identity is already activated' );
} else if ( error . code === 'INVALID_SIGNATURE' ) {
console . log ( 'Signature verification failed. Please try again.' );
} else if ( error . code === 'NOT_IDENTITY_OWNER' ) {
console . log ( 'You are not the owner of this identity' );
} else {
console . error ( 'Activation failed:' , error . message );
}
}
3. Store Activation Status
Track activation in your database:
const result = await activateIdentity ( tokenId );
await database . update ( 'identities' , {
tokenId: result . identity . tokenId ,
isActivated: true ,
activatedAt: result . identity . activatedAt ,
transactionHash: result . identity . transactionHash
});
4. Verify Signature Locally
Verify signature before sending to API:
import { ethers } from 'ethers' ;
function verifySignature ( message , signature , expectedAddress ) {
const recoveredAddress = ethers . utils . verifyMessage ( message , signature );
return recoveredAddress . toLowerCase () === expectedAddress . toLowerCase ();
}
// Before activation
const message = `Activate identity ${ tokenId } ` ;
const isValid = verifySignature ( message , signature , walletAddress );
if ( ! isValid ) {
throw new Error ( 'Invalid signature' );
}
// Proceed with activation
await activateIdentity ( tokenId , signature , walletAddress );
What Happens After Activation
Once activated, your identity:
Becomes Soulbound : Cannot be transferred to another wallet
Can Be Used as Parameter : Use alice.zks instead of wallet address in all APIs
Enables Features : Unlocks achievements, attestations, and trust scoring
Permanent : Cannot be deactivated or changed
Next Steps
After activating an identity:
Get Score - Check your ZKScore
Get Achievements - View available achievements
Create Attestation - Start building trust
Troubleshooting
”Invalid signature”
Cause : Signature doesn’t match the expected format or signer.
Solution :
Ensure you’re signing with the correct private key
Use the exact message format: Activate identity {tokenId}
Verify the wallet address matches the identity owner
”Already activated”
Cause : Identity has already been activated.
Solution :
Check identity status before attempting activation
This is not an error if the identity is already active
”Not identity owner”
Cause : The wallet address doesn’t match the identity owner.
Solution :
Verify you’re using the correct wallet
Check the identity owner address
Only the owner can activate their identity
”Transaction failed”
Cause : Blockchain transaction failed.
Solution :
Ensure wallet has sufficient gas
Wait a few minutes and try again
Check blockchain network status
Contact support if issue persists
Security Considerations
Private Key Safety
Never expose your private key:
// ❌ BAD: Hardcoded private key
const privateKey = '0x1234...' ;
// ✅ GOOD: Use environment variables
const privateKey = process . env . PRIVATE_KEY ;
// ✅ BETTER: Use secure key management
const privateKey = await keyManagementService . getKey ();
Signature Verification
Always verify signatures match expected addresses:
const recoveredAddress = ethers . utils . verifyMessage ( message , signature );
if ( recoveredAddress !== expectedAddress ) {
throw new Error ( 'Signature verification failed' );
}
Rate Limiting
Respect rate limits to avoid being blocked:
// Add delay between activations
await new Promise ( resolve => setTimeout ( resolve , 1000 ));