Activate Identity
curl --request POST \
--url https://api-mainnet.onzks.com/v1/identity/activate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tokenId": 123,
"signature": "<string>",
"walletAddress": "<string>"
}
'import requests
url = "https://api-mainnet.onzks.com/v1/identity/activate"
payload = {
"tokenId": 123,
"signature": "<string>",
"walletAddress": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({tokenId: 123, signature: '<string>', walletAddress: '<string>'})
};
fetch('https://api-mainnet.onzks.com/v1/identity/activate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-mainnet.onzks.com/v1/identity/activate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tokenId' => 123,
'signature' => '<string>',
'walletAddress' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-mainnet.onzks.com/v1/identity/activate"
payload := strings.NewReader("{\n \"tokenId\": 123,\n \"signature\": \"<string>\",\n \"walletAddress\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-mainnet.onzks.com/v1/identity/activate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tokenId\": 123,\n \"signature\": \"<string>\",\n \"walletAddress\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-mainnet.onzks.com/v1/identity/activate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"tokenId\": 123,\n \"signature\": \"<string>\",\n \"walletAddress\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": false,
"error": "IDENTITY_NOT_FOUND",
"message": "Identity with tokenId 12345 not found"
}
{
"success": false,
"error": "ALREADY_ACTIVATED",
"message": "Identity is already activated and soulbound"
}
{
"success": false,
"error": "INVALID_SIGNATURE",
"message": "Signature verification failed. Must be signed by identity owner."
}
{
"success": false,
"error": "NOT_IDENTITY_OWNER",
"message": "Wallet address does not match identity owner"
}
Identity
Activate Identity
Activate an identity to make it soulbound and non-transferable
POST
/
v1
/
identity
/
activate
Activate Identity
curl --request POST \
--url https://api-mainnet.onzks.com/v1/identity/activate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tokenId": 123,
"signature": "<string>",
"walletAddress": "<string>"
}
'import requests
url = "https://api-mainnet.onzks.com/v1/identity/activate"
payload = {
"tokenId": 123,
"signature": "<string>",
"walletAddress": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({tokenId: 123, signature: '<string>', walletAddress: '<string>'})
};
fetch('https://api-mainnet.onzks.com/v1/identity/activate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-mainnet.onzks.com/v1/identity/activate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tokenId' => 123,
'signature' => '<string>',
'walletAddress' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-mainnet.onzks.com/v1/identity/activate"
payload := strings.NewReader("{\n \"tokenId\": 123,\n \"signature\": \"<string>\",\n \"walletAddress\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-mainnet.onzks.com/v1/identity/activate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tokenId\": 123,\n \"signature\": \"<string>\",\n \"walletAddress\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-mainnet.onzks.com/v1/identity/activate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"tokenId\": 123,\n \"signature\": \"<string>\",\n \"walletAddress\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": false,
"error": "IDENTITY_NOT_FOUND",
"message": "Identity with tokenId 12345 not found"
}
{
"success": false,
"error": "ALREADY_ACTIVATED",
"message": "Identity is already activated and soulbound"
}
{
"success": false,
"error": "INVALID_SIGNATURE",
"message": "Signature verification failed. Must be signed by identity owner."
}
{
"success": false,
"error": "NOT_IDENTITY_OWNER",
"message": "Wallet address does not match identity owner"
}
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
number
required
The NFT token ID of the identity to activate (obtained from minting)
string
required
Cryptographic signature from the identity owner proving ownership
string
required
The wallet address of the identity owner (must match the minted identity)
Response
boolean
Indicates if the activation was successful
object
Show properties
Show properties
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"
}'
import { ethers } from 'ethers';
// Step 1: Generate signature
const signer = new ethers.Wallet(privateKey);
const message = `Activate identity ${tokenId}`;
const signature = await signer.signMessage(message);
// Step 2: Activate identity
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: 12345,
signature: signature,
walletAddress: signer.address
})
});
const data = await response.json();
console.log('Identity activated:', data.identity);
import requests
from eth_account import Account
from eth_account.messages import encode_defunct
# Step 1: Generate signature
private_key = 'your_private_key'
account = Account.from_key(private_key)
token_id = 12345
message = f"Activate identity {token_id}"
message_hash = encode_defunct(text=message)
signature = account.sign_message(message_hash).signature.hex()
# Step 2: Activate identity
response = requests.post(
'https://api.onzks.com/v1/identity/activate',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'tokenId': token_id,
'signature': signature,
'walletAddress': account.address
}
)
data = response.json()
print(f"Identity activated: {data['identity']}")
Response Example
{
"success": true,
"identity": {
"tokenId": 12345,
"name": "alice",
"ownerAddress": "0x742d35cc6635c0532925a3b844d1ff4e1321",
"isActivated": true,
"activatedAt": "2024-01-15T11:00:00Z",
"transactionHash": "0xdef456..."
}
}
Error Responses
{
"success": false,
"error": "IDENTITY_NOT_FOUND",
"message": "Identity with tokenId 12345 not found"
}
{
"success": false,
"error": "ALREADY_ACTIVATED",
"message": "Identity is already activated and soulbound"
}
{
"success": false,
"error": "INVALID_SIGNATURE",
"message": "Signature verification failed. Must be signed by identity owner."
}
{
"success": false,
"error": "NOT_IDENTITY_OWNER",
"message": "Wallet address does not match identity owner"
}
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
};
}
Using MetaMask
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.zksinstead 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
Related Endpoints
- Mint Identity - Create a new identity
- Get Identity - Retrieve identity information
- Check Availability - Check name availability
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));