Skip to main content

Register Subname (Free Tier)

Register a new ENS subname. First registration per wallet/IP is FREE.

Endpoint​

POST /api/subnames/{parent}

Authentication​

None required for free tier registration (but ownership is tracked by wallet address).

Free Tier Rules​

Important
  • ONE free registration per wallet address
  • ONE free registration per IP address
  • After using your free registration, use Purchase with x402 payment

Request Body​

{
"name": "alice",
"owner": "0x701B4937e6c943789ffA74CC8601813b2D87B454",
"records": {
"description": "My personal ENS subname",
"url": "https://alice.dev",
"com.twitter": "@alice"
}
}
FieldTypeRequiredDescription
namestringâś…Subname label (alphanumeric + hyphens, max 63 chars)
ownerstringâś…Ethereum address that will own the subname
recordsobject❌Optional ENS text records to set

Response (Success)​

{
"success": true,
"parent": "aboutme.eth",
"name": "alice",
"fullName": "alice.aboutme.eth",
"owner": "0x701B4937e6c943789ffA74CC8601813b2D87B454",
"freeTier": true,
"note": "This was your free registration. Additional names require payment.",
"timestamp": "2024-02-10T14:30:00.000Z"
}

Response (Free Tier Exhausted - 402)​

When free tier is used up, you'll receive a 402 Payment Required:

{
"error": true,
"code": "FREE_TIER_EXHAUSTED",
"message": "Wallet 0x701B...B454 has already used its free registration",
"reason": "WALLET_USED",
"details": {
"usedAt": "2024-02-09T18:30:00.000Z",
"usedFor": "alice.aboutme.eth"
},
"pricing": {
"price": 0.97,
"priceFormatted": "$0.97",
"tier": "standard",
"currency": "USDC",
"network": "Base (Chain ID 8453)"
},
"nextStep": "Use POST /api/subnames/aboutme.eth/purchase with x402 payment"
}

Examples​

cURL​

curl -X POST "https://api.web3identity.com/api/subnames/aboutme.eth" \
-H "Content-Type: application/json" \
-d '{
"name": "alice",
"owner": "0x701B4937e6c943789ffA74CC8601813b2D87B454"
}'

JavaScript​

async function registerSubname(parent, name, owner, records = {}) {
const response = await fetch(
`https://api.web3identity.com/api/subnames/${parent}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, owner, records })
}
);

const data = await response.json();

if (response.status === 402) {
// Free tier exhausted - need to use /purchase with payment
console.log(`Free tier used. Price: ${data.pricing.priceFormatted}`);
console.log(`Next step: ${data.nextStep}`);
return { needsPayment: true, ...data };
}

if (response.status === 409) {
// Name already taken
console.log('Name is already registered');
return { taken: true, ...data };
}

return data;
}

// Register with optional records
const result = await registerSubname(
'aboutme.eth',
'alice',
'0x701B4937e6c943789ffA74CC8601813b2D87B454',
{
description: 'Web3 developer',
'com.twitter': '@alice'
}
);

Full Registration Flow​

async function registerWithFallback(parent, name, owner, records) {
// 1. Check availability first
const availability = await fetch(
`https://api.web3identity.com/api/subnames/${parent}/${name}/available`
).then(r => r.json());

if (!availability.available) {
throw new Error(`${name}.${parent} is already taken`);
}

// 2. Try free registration
const result = await registerSubname(parent, name, owner, records);

if (result.success) {
console.log(`âś… Registered ${result.fullName} for FREE!`);
return result;
}

if (result.needsPayment) {
// 3. Redirect to payment flow
console.log(`Free tier exhausted. Price: ${result.pricing.priceFormatted}`);
// Use /purchase endpoint with x402 payment header
return { requiresPayment: true, price: result.pricing };
}

throw new Error(result.message);
}

Name Validation​

RuleValidInvalid
Alphanumericalice, bob123alice!, bob@123
Hyphens allowedmy-name, web-3-name, name-
Lowercase onlyaliceAlice, ALICE
Max 63 charsverylongname...Names over 63 chars

Error Responses​

StatusCodeDescription
400BAD_REQUESTMissing name or owner
400INVALID_ADDRESSOwner is not valid Ethereum address
400INVALID_NAMEName format is invalid
402FREE_TIER_EXHAUSTEDFree registration already used
409NAME_TAKENSubname is already registered
429RATE_LIMITEDRate limit exceeded
500SUBNAME_ERRORInternal server error