> ## Documentation Index
> Fetch the complete documentation index at: https://core.anylayer.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Activate Identity

> Activate an identity to make it soulbound and non-transferable

## 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.

<Warning>
  **Activation is permanent!** Once an identity is activated, it cannot be transferred or deactivated. Make sure you're activating the correct identity.
</Warning>

## Request Body

<ParamField body="tokenId" type="number" required>
  The NFT token ID of the identity to activate (obtained from minting)
</ParamField>

<ParamField body="signature" type="string" required>
  Cryptographic signature from the identity owner proving ownership
</ParamField>

<ParamField body="walletAddress" type="string" required>
  The wallet address of the identity owner (must match the minted identity)
</ParamField>

## Response

<ResponseField name="success" type="boolean">
  Indicates if the activation was successful
</ResponseField>

<ResponseField name="identity" type="object">
  <Expandable title="properties">
    <ResponseField name="tokenId" type="number">
      The NFT token ID
    </ResponseField>

    <ResponseField name="name" type="string">
      The ZKS ID name
    </ResponseField>

    <ResponseField name="ownerAddress" type="string">
      The wallet address that owns this identity
    </ResponseField>

    <ResponseField name="isActivated" type="boolean">
      Whether the identity is activated (always true after successful activation)
    </ResponseField>

    <ResponseField name="activatedAt" type="string">
      ISO 8601 timestamp of when the identity was activated
    </ResponseField>

    <ResponseField name="transactionHash" type="string">
      The blockchain transaction hash for the activation
    </ResponseField>
  </Expandable>
</ResponseField>

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  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"
    }'
  ```

  ```javascript JavaScript theme={null}
  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);
  ```

  ```python Python theme={null}
  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']}")
  ```
</CodeGroup>

## Response Example

```json theme={null}
{
  "success": true,
  "identity": {
    "tokenId": 12345,
    "name": "alice",
    "ownerAddress": "0x742d35cc6635c0532925a3b844d1ff4e1321",
    "isActivated": true,
    "activatedAt": "2024-01-15T11:00:00Z",
    "transactionHash": "0xdef456..."
  }
}
```

## Error Responses

<ResponseExample>
  ```json 404 Not Found theme={null}
  {
    "success": false,
    "error": "IDENTITY_NOT_FOUND",
    "message": "Identity with tokenId 12345 not found"
  }
  ```

  ```json 400 Bad Request - Already Activated theme={null}
  {
    "success": false,
    "error": "ALREADY_ACTIVATED",
    "message": "Identity is already activated and soulbound"
  }
  ```

  ```json 401 Unauthorized - Invalid Signature theme={null}
  {
    "success": false,
    "error": "INVALID_SIGNATURE",
    "message": "Signature verification failed. Must be signed by identity owner."
  }
  ```

  ```json 403 Forbidden - Not Owner theme={null}
  {
    "success": false,
    "error": "NOT_IDENTITY_OWNER",
    "message": "Wallet address does not match identity owner"
  }
  ```
</ResponseExample>

## Signature Generation

### Using ethers.js

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
// 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:

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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:

1. **Becomes Soulbound**: Cannot be transferred to another wallet
2. **Can Be Used as Parameter**: Use `alice.zks` instead of wallet address in all APIs
3. **Enables Features**: Unlocks achievements, attestations, and trust scoring
4. **Permanent**: Cannot be deactivated or changed

## Next Steps

After activating an identity:

1. **[Get Score](/api-reference/scores/get-score)** - Check your ZKScore
2. **[Get Achievements](/api-reference/achievements/get-user-achievements)** - View available achievements
3. **[Create Attestation](/api-reference/trust-layer/create-attestation)** - Start building trust

## Related Endpoints

* [Mint Identity](/api-reference/identity/mint-identity) - Create a new identity
* [Get Identity](/api-reference/identity/get-identity) - Retrieve identity information
* [Check Availability](/api-reference/identity/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:

```javascript theme={null}
// ❌ 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:

```javascript theme={null}
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:

```javascript theme={null}
// Add delay between activations
await new Promise(resolve => setTimeout(resolve, 1000));
```
