> For the complete documentation index, see [llms.txt](https://abc.bharatblockchain.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://abc.bharatblockchain.io/hedera/tutorials/token-service/non-fungible-token.md).

# Non-fungible Token

In this tutorial, we'll guide you through the process of working with Hedera Token Service (HTS) for non-fungible tokens (NFTs) using JavaScript scripts. These scripts cover essential operations such as creating an NFT, getting NFT information, minting and transferring NFTs, transferring and burning NFTs.

#### Prerequisites

Before you start, make sure you have the following:

* [Node.js](https://nodejs.org/) installed on your machine.
* A Hedera Hashgraph account for testing purposes.
* Hedera JavaScript SDK installed in your project.

#### Step 1: Set Up Environment

1. Create a new directory for your project and navigate into it.

```bash
mkdir HederaNFTTutorial
cd HederaNFTTutorial
```

2. Initialise your Node.js project and install the necessary dependencies.

```bash
npm init -y
npm install @hashgraph/sdk dotenv
```

3. Create a `.env` file to store your Hedera account details.

```bash
MY_ACCOUNT_ID=your_account_id
MY_PRIVATE_KEY=your_private_key
OTHER_ACCOUNT_ID=another_account_id
OTHER_PRIVATE_KEY=another_private_key
```

#### Step 2: Write NFT Creation Script

Create a file named `createNFT.js` and add the script for NFT creation.

```javascript
const {
    TokenCreateTransaction,
    Client,
    TokenType,
    TokenSupplyType,
    PrivateKey,
    AccountBalanceQuery
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });

const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);

// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
    myPrivateKey == null ) {
    throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}

// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();

client.setOperator(myAccountId, myPrivateKey);

async function main() {

    //Create the NFT
    let nftCreate = await new TokenCreateTransaction()
        .setTokenName("polyversity")
        .setTokenSymbol("POL")
        .setTokenType(TokenType.NonFungibleUnique)
        .setDecimals(0)
        .setInitialSupply(0)
        .setTreasuryAccountId(myAccountId)
        .setSupplyType(TokenSupplyType.Finite)
        .setMaxSupply(5)
        .setSupplyKey(myPrivateKey)
        .freezeWith(client);

    //Sign the transaction with the treasury key
    let nftCreateTxSign = await nftCreate.sign(myPrivateKey);

    //Submit the transaction to a Hedera network
    let nftCreateSubmit = await nftCreateTxSign.execute(client);

    //Get the transaction receipt
    let nftCreateRx = await nftCreateSubmit.getReceipt(client);

    //Get the token ID
    let tokenId = nftCreateRx.tokenId;

    //Log the token ID
    console.log(`- Created NFT with Token ID: ${tokenId} \n`);

    const balanceCheckTx = await new AccountBalanceQuery().setAccountId(myAccountId).execute(client);

    console.log(`- User balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} units of token ID ${tokenId}`);

    process.exit();
}

main();

```

#### Step 3: Write Get NFT Info Script

Create a file named `getNFTInfo.js` and add the script for getting NFT information.

```javascript
const {
    TokenNftInfoQuery,
    Client,
    PrivateKey,
    NftId,
    TokenId,
    AccountId
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });

const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);

const tokenId = process.env.NFT_ID;

// The index of the NFT on the token object - this is the actual NFT
const NFTTokenIndex = 1;

// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
    myPrivateKey == null ) {
    throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}

// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();

client.setOperator(myAccountId, myPrivateKey);

async function main() {
    console.log(`Searching for NFT ID ${NFTTokenIndex} on token ${tokenId}`);
    
    //Returns the info for the specified NFT ID
    const nftInfos = await new TokenNftInfoQuery()
        .setNftId(new NftId(TokenId.fromString(tokenId), NFTTokenIndex))
        .execute(client);

    console.log("The ID of the token is: " + nftInfos[0].nftId.tokenId.toString());
    console.log("The serial of the token is: " + nftInfos[0].nftId.serial.toString());
    console.log("The metadata of the token is: " + nftInfos[0].metadata.toString());
    console.log("Current owner: " + new AccountId(nftInfos[0].accountId).toString());

    process.exit();
}

main();

```

#### Step 4: Write NFT Mint and Transfer Script

Create a file named `mintTransferNFT.js` and add the script for minting and transferring NFTs.

```javascript
const {
    TokenMintTransaction,
    Client,
    PrivateKey,
    AccountBalanceQuery, TokenAssociateTransaction, TransferTransaction, Wallet
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });

const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);

const otherAccountId = process.env.OTHER_ACCOUNT_ID;
const otherPrivateKey = PrivateKey.fromString(process.env.OTHER_PRIVATE_KEY);

const tokenId = process.env.NFT_ID;

// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
    myPrivateKey == null ) {
    throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}

// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();

client.setOperator(myAccountId, myPrivateKey);

const wallet = new Wallet(
    otherAccountId,
    otherPrivateKey
);

async function main() {
    //IPFS content identifiers for which we will create a NFT
    CID = "bafybeig5vygdwxnahwgp7vku6kyz4e3hdjsg4uikfz5sujbsummozw3wp4";

    // Mint new NFT
    let mintTx = await new TokenMintTransaction()
        .setTokenId(tokenId)
        .setMetadata([Buffer.from(CID)])
        .freezeWith(client);

    //Sign the transaction with the supply key
    let mintTxSign = await mintTx.sign(myPrivateKey);

    //Submit the transaction to a Hedera network
    let mintTxSubmit = await mintTxSign.execute(client);

    //Get the transaction receipt
    let mintRx = await mintTxSubmit.getReceipt(client);

    //Log the serial number
    console.log(`- Created NFT ${tokenId} with serial: ${mintRx.serials[0].low} \n`);

    let balanceCheckTx = await new AccountBalanceQuery().setAccountId(myAccountId).execute(client);

    console.log(`- User balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} units of token ID ${tokenId}`);

    //  Before an account that is not the treasury for a token can receive or send this specific token ID, the account
    //  must become “associated” with the token.
    let associateBuyerTx = await new TokenAssociateTransaction()
        .setAccountId(wallet.accountId)
        .setTokenIds([tokenId])
        .freezeWith(client)
        .sign(otherPrivateKey)

    //SUBMIT THE TRANSACTION
    let associateBuyerTxSubmit = await associateBuyerTx.execute(client);

    //GET THE RECEIPT OF THE TRANSACTION
    let associateBuyerRx = await associateBuyerTxSubmit.getReceipt(client);

    //LOG THE TRANSACTION STATUS
    console.log(`- Token association with the users account: ${associateBuyerRx.status} \n`);

    // Check the balance before the transfer for the treasury account
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(myAccountId).execute(client);
    console.log(`- Treasury balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    // Check the balance before the transfer for Alice's account
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(otherAccountId).execute(client);
    console.log(`- Buyer's balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    // Transfer the NFT from treasury to Alice
    // Sign with the treasury key to authorize the transfer
    let tokenTransferTx = await new TransferTransaction()
        .addNftTransfer(tokenId, 1, myAccountId, otherAccountId)
        .freezeWith(client)
        .sign(myPrivateKey);

    let tokenTransferSubmit = await tokenTransferTx.execute(client);
    let tokenTransferRx = await tokenTransferSubmit.getReceipt(client);

    console.log(`\n- NFT transfer from Treasury to Buyer: ${tokenTransferRx.status} \n`);

    // Check the balance of the treasury account after the transfer
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(myAccountId).execute(client);
    console.log(`- Treasury balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    // Check the balance of Alice's account after the transfer
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(otherAccountId).execute(client);
    console.log(`- Buyer's balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    process.exit();
}

main();

```

#### Step 5: Write NFT Transfer and Burn Script

Create a file named `transferBurnNFT.js` and add the script for transferring and burning NFTs.

```javascript
const {
    TokenBurnTransaction,
    Client,
    PrivateKey,
    AccountBalanceQuery,
    TransferTransaction
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });

const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);

const otherAccountId = process.env.OTHER_ACCOUNT_ID;
const otherPrivateKey = PrivateKey.fromString(process.env.OTHER_PRIVATE_KEY);

const tokenId = process.env.NFT_ID;

// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
    myPrivateKey == null ) {
    throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}

// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();

client.setOperator(myAccountId, myPrivateKey);

async function main() {

    // Check the balance before the transfer for the treasury account
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(myAccountId).execute(client);
    console.log(`- Treasury balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    // Check the balance before the transfer for the buyer's account
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(otherAccountId).execute(client);
    console.log(`- Buyer's balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    // Transfer the NFT from treasury to the buyer
    // Sign with the treasury key to authorize the transfer
    let tokenTransferTx = await new TransferTransaction()
        .addNftTransfer(tokenId, 1, otherAccountId, myAccountId)
        .freezeWith(client)
        .sign(otherPrivateKey);

    let tokenTransferSubmit = await tokenTransferTx.execute(client);
    let tokenTransferRx = await tokenTransferSubmit.getReceipt(client);

    console.log(`\n- NFT transfer from Buyer to Treasury: ${tokenTransferRx.status} \n`);

    // Check the balance of the treasury account after the transfer
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(myAccountId).execute(client);
    console.log(`- Treasury balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    // Check the balance of the buyer's account after the transfer
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(otherAccountId).execute(client);
    console.log(`- Buyer's balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    //Burn the nft and freeze the unsigned transaction for manual signing
    const transaction = await new TokenBurnTransaction()
        .setTokenId(tokenId)
        .setSerials([1])
        .freezeWith(client);

    //Sign with the supply private key of the token
    const signTx = await transaction.sign(myPrivateKey);

    //Submit the transaction to a Hedera network
    const txResponse = await signTx.execute(client);

    //Request the receipt of the transaction
    const receipt = await txResponse.getReceipt(client);

    //Get the transaction consensus status
    const transactionStatus = receipt.status;

    console.log("The transaction consensus status " +transactionStatus.toString());

    // Check the balance of the treasury account after the transfer
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(myAccountId).execute(client);
    console.log(`- Treasury balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    // Check the balance of the buyer's account after the transfer
    balanceCheckTx = await new AccountBalanceQuery().setAccountId(otherAccountId).execute(client);
    console.log(`- Buyer's balance: ${balanceCheckTx.tokens._map.get(tokenId.toString())} NFTs of ID ${tokenId}`);

    process.exit();
}

main();

```

#### Example Metadata

In your non-fungible token scripts, you can customize the token properties using metadata. An example metadata file, `metadataExample.json`, is provided below. This file contains sample metadata that you can use as a template or modify according to your specific requirements.

Feel free to explore and utilize the information in `metadataExample.json` to enhance the details associated with your non-fungible tokens during creation, minting, or other relevant operations. Remember to add the relevant code in required script for reading this metadata file.

Create a file named `metadataExample.json` and add the below script.

```json
{
  "name": "Ticket #1",
  "description": "This is one of the few tickets to THE event.",
  "image": "https://i.pinimg.com/originals/f9/ef/83/f9ef835e39ed1f52c1c89109c7c330fd.jpg",
  "properties": {
    "latitude": "37°14'09.8N",
    "Longitude": "115°48'03.9W",
    "date": "22.12.2051",
    "info": "bring some pineapples"
  }
}
```

#### Step 6: Run the Scripts

Execute each script in the order of NFT creation, getting NFT info, minting and transferring, and transferring and burning. Ensure that you are following the proper sequence.

```bash
node createNFT.js
node getNFTInfo.js
node mintTransferNFT.js
node transferBurnNFT.js
```

#### Conclusion

Congratulations! You have successfully executed scripts for various Hedera Token Service operations related to non-fungible tokens (NFTs). This tutorial covers fundamental steps, and you can further explore advanced features and integrations based on your specific use case.
