Mint Identity
curl --request POST \
--url https://api-mainnet.onzks.com/v1/identity/mint \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"walletAddress": "<string>",
"metadata": {
"avatar": "<string>",
"bio": "<string>",
"socialLinks": {}
}
}
'import requests
url = "https://api-mainnet.onzks.com/v1/identity/mint"
payload = {
"name": "<string>",
"walletAddress": "<string>",
"metadata": {
"avatar": "<string>",
"bio": "<string>",
"socialLinks": {}
}
}
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({
name: '<string>',
walletAddress: '<string>',
metadata: {avatar: '<string>', bio: '<string>', socialLinks: {}}
})
};
fetch('https://api-mainnet.onzks.com/v1/identity/mint', 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/mint",
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([
'name' => '<string>',
'walletAddress' => '<string>',
'metadata' => [
'avatar' => '<string>',
'bio' => '<string>',
'socialLinks' => [
]
]
]),
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/mint"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"metadata\": {\n \"avatar\": \"<string>\",\n \"bio\": \"<string>\",\n \"socialLinks\": {}\n }\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/mint")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"metadata\": {\n \"avatar\": \"<string>\",\n \"bio\": \"<string>\",\n \"socialLinks\": {}\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-mainnet.onzks.com/v1/identity/mint")
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 \"name\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"metadata\": {\n \"avatar\": \"<string>\",\n \"bio\": \"<string>\",\n \"socialLinks\": {}\n }\n}"
response = http.request(request)
puts response.read_body{
"success": false,
"error": "INVALID_NAME_FORMAT",
"message": "Name must be 3-32 characters, lowercase letters, numbers, and hyphens only"
}
{
"success": false,
"error": "NAME_ALREADY_TAKEN",
"message": "The name 'alice' is already taken",
"suggestions": ["alice1", "alice-zk", "alice2024"]
}
{
"success": false,
"error": "INVALID_WALLET_ADDRESS",
"message": "Invalid Ethereum address format"
}
{
"success": false,
"error": "RATE_LIMIT_EXCEEDED",
"message": "Too many mint requests. Please try again later."
}
Identity
Mint Identity
Create a new ZKScore identity with a unique ZKS ID
POST
/
v1
/
identity
/
mint
Mint Identity
curl --request POST \
--url https://api-mainnet.onzks.com/v1/identity/mint \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"walletAddress": "<string>",
"metadata": {
"avatar": "<string>",
"bio": "<string>",
"socialLinks": {}
}
}
'import requests
url = "https://api-mainnet.onzks.com/v1/identity/mint"
payload = {
"name": "<string>",
"walletAddress": "<string>",
"metadata": {
"avatar": "<string>",
"bio": "<string>",
"socialLinks": {}
}
}
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({
name: '<string>',
walletAddress: '<string>',
metadata: {avatar: '<string>', bio: '<string>', socialLinks: {}}
})
};
fetch('https://api-mainnet.onzks.com/v1/identity/mint', 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/mint",
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([
'name' => '<string>',
'walletAddress' => '<string>',
'metadata' => [
'avatar' => '<string>',
'bio' => '<string>',
'socialLinks' => [
]
]
]),
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/mint"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"metadata\": {\n \"avatar\": \"<string>\",\n \"bio\": \"<string>\",\n \"socialLinks\": {}\n }\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/mint")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"metadata\": {\n \"avatar\": \"<string>\",\n \"bio\": \"<string>\",\n \"socialLinks\": {}\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-mainnet.onzks.com/v1/identity/mint")
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 \"name\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"metadata\": {\n \"avatar\": \"<string>\",\n \"bio\": \"<string>\",\n \"socialLinks\": {}\n }\n}"
response = http.request(request)
puts response.read_body{
"success": false,
"error": "INVALID_NAME_FORMAT",
"message": "Name must be 3-32 characters, lowercase letters, numbers, and hyphens only"
}
{
"success": false,
"error": "NAME_ALREADY_TAKEN",
"message": "The name 'alice' is already taken",
"suggestions": ["alice1", "alice-zk", "alice2024"]
}
{
"success": false,
"error": "INVALID_WALLET_ADDRESS",
"message": "Invalid Ethereum address format"
}
{
"success": false,
"error": "RATE_LIMIT_EXCEEDED",
"message": "Too many mint requests. Please try again later."
}
Overview
Mint a new identity NFT (SBT) with a unique ZKS ID. This creates a non-transferable identity token that can be activated to become soulbound. Once minted, the identity can be used across the ZKScore ecosystem.Identity names must be unique across the platform. Use the Check Availability endpoint to verify name availability before minting.
Request Body
string
required
The desired ZKS ID name (without .zks suffix). Must be 3-32 characters, lowercase letters, numbers, and hyphens only. Cannot start or end with a hyphen.
string
required
The Ethereum wallet address that will own this identity. Must be a valid address format.
object
Response
boolean
Indicates if the minting was successful
object
Show properties
Show properties
number
The NFT token ID of the minted identity
string
The ZKS ID name (without .zks suffix)
string
The wallet address that owns this identity
boolean
Whether the identity is activated (always false after minting)
string
ISO 8601 timestamp of when the identity was minted
string
The blockchain transaction hash
Examples
curl -X POST https://api.onzks.com/v1/identity/mint \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "alice",
"walletAddress": "0x742d35Cc6635C0532925a3b844D1FF4e1321",
"metadata": {
"avatar": "https://example.com/avatar.png",
"bio": "DeFi enthusiast and protocol researcher"
}
}'
const response = 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: 'alice',
walletAddress: '0x742d35Cc6635C0532925a3b844D1FF4e1321',
metadata: {
avatar: 'https://example.com/avatar.png',
bio: 'DeFi enthusiast and protocol researcher'
}
})
});
const data = await response.json();
console.log('Identity minted:', data.identity);
import requests
response = requests.post(
'https://api.onzks.com/v1/identity/mint',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'name': 'alice',
'walletAddress': '0x742d35Cc6635C0532925a3b844D1FF4e1321',
'metadata': {
'avatar': 'https://example.com/avatar.png',
'bio': 'DeFi enthusiast and protocol researcher'
}
}
)
data = response.json()
print(f"Identity minted: {data['identity']}")
Response Example
{
"success": true,
"identity": {
"tokenId": 12345,
"name": "alice",
"ownerAddress": "0x742d35cc6635c0532925a3b844d1ff4e1321",
"isActivated": false,
"createdAt": "2024-01-15T10:30:00Z",
"transactionHash": "0xabc123..."
}
}
Error Responses
{
"success": false,
"error": "INVALID_NAME_FORMAT",
"message": "Name must be 3-32 characters, lowercase letters, numbers, and hyphens only"
}
{
"success": false,
"error": "NAME_ALREADY_TAKEN",
"message": "The name 'alice' is already taken",
"suggestions": ["alice1", "alice-zk", "alice2024"]
}
{
"success": false,
"error": "INVALID_WALLET_ADDRESS",
"message": "Invalid Ethereum address format"
}
{
"success": false,
"error": "RATE_LIMIT_EXCEEDED",
"message": "Too many mint requests. Please try again later."
}
Name Validation Rules
Valid Names
✅ Accepted formats:alice- Simple namedefi-master- With hyphenuser123- With numbersmy-identity-2024- Multiple hyphens and numbers
Invalid Names
❌ Rejected formats:al- Too short (minimum 3 characters)-alice- Starts with hyphenalice-- Ends with hyphenAlice- Contains uppercasealice.eth- Contains periodalice@zks- Contains special charactersthis-name-is-way-too-long-to-be-valid- Too long (maximum 32 characters)
Use Cases
1. User Onboarding
Create an identity during user registration:async function onboardUser(walletAddress, desiredName) {
try {
// Check availability first
const available = await checkAvailability(desiredName);
if (!available) {
throw new Error('Name not available');
}
// Mint identity
const identity = await mintIdentity({
name: desiredName,
walletAddress: walletAddress
});
console.log(`Identity created: ${identity.name}.zks`);
return identity;
} catch (error) {
console.error('Onboarding failed:', error);
throw error;
}
}
2. Batch Identity Creation
Create multiple identities for a team or organization:async function createTeamIdentities(teamMembers) {
const identities = [];
for (const member of teamMembers) {
const identity = await mintIdentity({
name: member.username,
walletAddress: member.address,
metadata: {
bio: member.role,
socialLinks: member.socials
}
});
identities.push(identity);
// Rate limiting: wait 1 second between requests
await new Promise(resolve => setTimeout(resolve, 1000));
}
return identities;
}
3. Identity with Custom Metadata
Create an identity with rich metadata:const identity = await mintIdentity({
name: 'defi-trader',
walletAddress: '0x742d35Cc6635C0532925a3b844D1FF4e1321',
metadata: {
avatar: 'https://cdn.example.com/avatars/trader.png',
bio: 'Professional DeFi trader specializing in yield farming',
socialLinks: {
twitter: 'https://twitter.com/defitrader',
github: 'https://github.com/defitrader',
discord: 'defitrader#1234'
}
}
});
Best Practices
1. Check Availability First
Always check name availability before attempting to mint:const available = await checkAvailability('alice');
if (available) {
await mintIdentity({ name: 'alice', walletAddress: address });
}
2. Handle Errors Gracefully
Provide helpful feedback when minting fails:try {
const identity = await mintIdentity({ name, walletAddress });
} catch (error) {
if (error.code === 'NAME_ALREADY_TAKEN') {
// Show suggestions to user
console.log('Try these names:', error.suggestions);
} else if (error.code === 'INVALID_NAME_FORMAT') {
// Show validation rules
console.log('Name must be 3-32 characters, lowercase only');
}
}
3. Store Transaction Hash
Save the transaction hash for verification:const identity = await mintIdentity({ name, walletAddress });
await database.save({
userId: user.id,
tokenId: identity.tokenId,
transactionHash: identity.transactionHash,
createdAt: identity.createdAt
});
4. Activate After Minting
Remember to activate the identity to make it soulbound:// Step 1: Mint
const identity = await mintIdentity({ name, walletAddress });
// Step 2: Activate (makes it soulbound)
await activateIdentity({ tokenId: identity.tokenId });
Next Steps
After minting an identity:- Activate Identity - Make the identity soulbound
- Get Identity - Retrieve identity information
- Get Score - Check the user’s ZKScore
Related Endpoints
- Activate Identity - Activate a minted identity
- Check Availability - Check if a name is available
- Get Identity - Retrieve identity information
Troubleshooting
”Name already taken”
Cause: The requested name is already registered by another user. Solution:- Use the suggestions provided in the error response
- Try a different name with numbers or hyphens
- Check availability before minting
”Invalid name format”
Cause: The name doesn’t meet validation requirements. Solution:- Ensure name is 3-32 characters
- Use only lowercase letters, numbers, and hyphens
- Don’t start or end with a hyphen
”Transaction failed”
Cause: Blockchain transaction failed or was reverted. Solution:- Check wallet has sufficient gas
- Verify wallet address is correct
- Try again after a few minutes
- Contact support if issue persists
Rate Limits
Identity minting is subject to rate limits:- Free tier: 10 mints per hour
- Starter tier: 100 mints per hour
- Professional tier: 1,000 mints per hour
- Enterprise tier: Custom limits
429 Too Many Requests error.