The benefit of the Handle Standard is that everything you might want to know about the Handle is openly available on-chain (such as an associated address, additional Handles, etc). This means that while the official Handle API might be more convenient, it is by no means required.
While documenting the process of setting up a Cardano Node and the Wallet REST & GraphQL APIs are beyond the scope of this article, you can find detailed instructions here:
consthandleName='web3';constpolicyID='f0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9a';// A blank Handle name should always be ignored.if (handleName.length===0) {// Handle error.}// Convert handleName to hex encoding.constassetName=Buffer.from(handleName).toString('hex');// Fetch matching address for the asset.constdata=awaitfetch(`https://cardano-mainnet.blockfrost.io/api/v0/assets/${policyID}${assetName}/addresses`, { headers: {// Your Blockfrost API key project_id:process.env.BLOCKFROST_API_KEY,'Content-Type':'application/json' } }).then(res =>res.json());if (data?.error) {// Handle error.}const [{ address }] = data;console.log(address); // addr1qx3c9...
queryGetHandleByFingerprint { assets( limit:2 where: {fingerprint: {_eq: "asset1na7l64eeutwm96gyzl3rkgknwpu8qz4fpuzah0" } } ) { tokenMints( # Always expect a single result. # Getting 2 results would indicate a double-mint. # This is a security check, but not required. limit: 2 ) { transaction { outputs ( limit: 1 where: {tokens: {asset: {fingerprint: {_eq: "asset1na7l64eeutwm96gyzl3rkgknwpu8qz4fpuzah0" } } } } ) { address } } } }}
Get All Handles by Address
constpolicyID='f0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9a';constaddress='addr1...';// Fetch data about an address.constdata=awaitfetch(`https://cardano-mainnet.blockfrost.io/api/v0/addresses/${address}`, { headers: {// Your Blockfrost API key project_id:process.env.BLOCKFROST_API_KEY,'Content-Type':'application/json' } }).then(res =>res.json());if (data?.error) {// Handle error.}consthandles=data.amount.filter(({ unit }) =>unit.includes(policyID)).map(({ unit }) => {consthexName=unit.replace(policyID,'');constutf8Name=Buffer.from(hexName,'hex').toString('utf8');return utf8Name; });console.log(handles); // ['handle1', 'handle2', ...]
queryGetHandlesByAddress { utxos ( where: {address: {_eq: "addr1..." } } ) { tokens { asset { # Filter results by matching policyIDs to get Handles. policyId assetName } } }}