This README documents the API endpoints for querying main domains by Solana pubkey, both individually and in batch.
Website: https://alldomains.id
Endpoint:
GET /api/main-domain/[pubkey]
Description: Retrieve the main domain associated with a single Solana pubkey.
Example Request:
curl https://alldomains.id/api/main-domain/2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67
Example Response:
{
"status": "success",
"error": null,
"msg": null,
"mainDomain": "miester.bonk"
}
Error Response:
{
"status": "error",
"error": "Main Domain does not exist",
"msg": null,
"mainDomain": null
}
Endpoint:
POST /api/main-domain/batch
Description: Retrieve main domains for up to 100 Solana pubkeys in a single request.
Example Request:
curl -X POST https://alldomains.id/api/main-domain/batch \
-H "Content-Type: application/json" \
-d '{"pubkeys": ["2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67", "7pYxSDRV6qwSSHAxxJ3MtGUycEenz85rSdmnQTJD73wY"]}'
Example Response:
{
"status": "success",
"error": null,
"msg": null,
"mainDomains": [
{
"pubkey": "2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67",
"mainDomain": "miester.bonk",
"nameAccount": "<base58_pubkey>"
},
{
"pubkey": "7pYxSDRV6qwSSHAxxJ3MtGUycEenz85rSdmnQTJD73wY",
"mainDomain": null,
"nameAccount": null
}
]
}
Error Response (missing pubkeys):
{
"status": "error",
"error": "pubkeys are missing",
"msg": "Please specify pubkeys. i.e. /api/main-domain/batch",
"owner": null
}
Error Response (too many pubkeys):
{
"status": "error",
"error": "pubkeys length should be less than 100",
"msg": "Please specify pubkeys. i.e. /api/main-domain/batch",
"owner": null
}
// /app/api/main-domain/[pubkey]/route.ts
import {
findMainDomain,
findNameHouse,
findNftRecord,
findTldHouse,
getMintOwner,
MainDomain,
NameRecordHeader,
} from "@onsol/tldparser";
import { Connection, PublicKey } from "@solana/web3.js";
export const getMainDomainV2 = async (
connection: Connection,
pubkey: string
): Promise<{
pubkey: string;
mainDomain: string | undefined;
nameAccount: PublicKey | undefined;
}> => {
const mainDomainKey = findMainDomain(new PublicKey(pubkey))[0];
const mainDomainAccount = await connection.getAccountInfo(mainDomainKey);
if (!mainDomainAccount?.data) {
return { pubkey, nameAccount: undefined, mainDomain: undefined };
}
const mainDomainData = MainDomain.fromAccountInfo(mainDomainAccount)[0];
const nameAccount = mainDomainData.nameAccount;
const nameAccountInfo = await connection.getAccountInfo(nameAccount);
if (!nameAccountInfo) {
return { pubkey, nameAccount, mainDomain: undefined };
}
const nameAccountData = NameRecordHeader.fromAccountInfo(nameAccountInfo);
const tld = mainDomainData.tld;
const [tldHouseKey] = findTldHouse(tld);
const [nameHouseKey] = findNameHouse(tldHouseKey);
const [nftRecordKey] = findNftRecord(nameAccount, nameHouseKey);
// NFT owner check
if (nameAccountData.owner?.toString() === nftRecordKey.toString()) {
const mintOwner = await getMintOwner(connection, nftRecordKey);
if (mintOwner?.toString() !== pubkey) {
return { pubkey, nameAccount, mainDomain: undefined };
}
return {
pubkey,
nameAccount,
mainDomain: mainDomainData.domain + mainDomainData.tld,
};
}
// Name record owner check
if (nameAccountData.owner?.toString() !== pubkey) {
return { pubkey, nameAccount, mainDomain: undefined };
}
// Expiry check
const expiresAtIsValid = nameAccountData.expiresAt.getTime() !== 0;
if (expiresAtIsValid && nameAccountData.expiresAt.getTime() < Date.now()) {
return { pubkey, nameAccount, mainDomain: undefined };
}
return {
pubkey,
nameAccount,
mainDomain: mainDomainData.domain + mainDomainData.tld,
};
};
// /app/api/main-domain/batch/route.ts
import {
findMainDomain,
findNameHouse,
findNftRecord,
findTldHouse,
getMintOwner,
MainDomain,
NameRecordHeader,
} from "@onsol/tldparser";
import { AccountInfo, Connection, PublicKey } from "@solana/web3.js";
const getMultipleMainDomains = async (
connection: Connection,
pubkeys: string[],
): Promise<{
pubkey: string;
mainDomain: string | undefined;
nameAccount: PublicKey | undefined;
}[]> => {
const mainDomainKeys = pubkeys.map(
(pubkey) => findMainDomain(new PublicKey(pubkey))[0],
);
const mainDomainAccounts =
await connection.getMultipleAccountsInfo(mainDomainKeys);
const mainDomainWithNameAccounts = pubkeys.map((pubkey, index) => {
const mainDomainAccount = mainDomainAccounts[index];
if (!!mainDomainAccount?.data) {
const mainDomainData = MainDomain.fromAccountInfo(mainDomainAccount)[0];
const nameAccount = mainDomainData.nameAccount;
return {
pubkey: pubkey.toString(),
nameAccount,
mainDomain: mainDomainData.domain + mainDomainData.tld,
};
}
return {
pubkey: pubkey.toString(),
nameAccount: undefined,
mainDomain: undefined,
};
});
const nameAccounts = mainDomainWithNameAccounts.map(
(item) => item.nameAccount,
);
const filteredNameAccountsWithIndex = nameAccounts
.map((pk, idx) => (pk ? { pk, idx } : undefined))
.filter((x): x is { pk: PublicKey; idx: number } => !!x);
const filteredNameAccounts = filteredNameAccountsWithIndex.map((x) => x.pk);
const nameAccountsInfo =
await connection.getMultipleAccountsInfo(filteredNameAccounts);
const infoByOriginalIdx = new Array<AccountInfo<Buffer> | null>(
nameAccounts.length,
).fill(null);
filteredNameAccountsWithIndex.forEach((entry, i) => {
infoByOriginalIdx[entry.idx] = nameAccountsInfo[i];
});
const result = await Promise.all(
mainDomainWithNameAccounts.map(async (item, index) => {
const nameAccount = item.nameAccount;
const info = infoByOriginalIdx[index];
if (!nameAccount || !info) {
return { ...item };
}
const nameAccountData = NameRecordHeader.fromAccountInfo(info);
const tld = item.mainDomain?.split(".")[1];
const [tldHouseKey] = findTldHouse(tld);
const [nameHouseKey] = findNameHouse(tldHouseKey);
const [nftRecordKey] = findNftRecord(nameAccount, nameHouseKey);
const isNftRecordOwner =
nameAccountData.owner?.toString() === nftRecordKey.toString();
if (isNftRecordOwner) {
const mintOwner = await getMintOwner(connection, nftRecordKey);
if (mintOwner?.toString() != pubkeys[index]) {
return {
pubkey: pubkeys[index].toString(),
nameAccount,
mainDomain: undefined,
};
}
return { ...item };
}
if (nameAccountData.owner?.toString() != pubkeys[index]) {
return {
pubkey: pubkeys[index].toString(),
nameAccount,
mainDomain: undefined,
};
}
const expiresAtIsValid = nameAccountData.expiresAt.getTime() != 0;
if (
expiresAtIsValid &&
nameAccountData.expiresAt.getTime() < Date.now()
) {
return {
pubkey: pubkeys[index].toString(),
nameAccount,
mainDomain: undefined,
};
}
return { ...item };
}),
);
return result;
};
const pubkey = "2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67";
fetch(`https://alldomains.id/api/main-domain/${pubkey}`)
.then(res => res.json())
.then(data => {
if (data.status === "success") {
console.log("Main domain:", data.mainDomain);
} else {
console.error("Error:", data.error);
}
});
const pubkeys = [
"2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67",
"7pYxSDRV6qwSSHAxxJ3MtGUycEenz85rSdmnQTJD73wY"
];
fetch("https://alldomains.id/api/main-domain/batch", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ pubkeys })
})
.then(res => res.json())
.then(data => {
if (data.status === "success") {
data.mainDomains.forEach(item => {
console.log(item.pubkey, "=>", item.mainDomain);
});
} else {
console.error("Error:", data.error);
}
});
- The batch endpoint is limited to 100 pubkeys per request.
- All endpoints use the same Solana RPC endpoint as configured in the code.
© alldomains.id