Hedera
  • Welcome to Hedera — let’s build the future
  • Getting Started
    • Environment Setup
    • Web2 Developers
      • Transfer HBAR
      • Create a Token
      • Create a Topic
    • EVM Developers
      • Deploy a Contract
  • Tutorials
    • Smart Contracts
      • How to Mint & Burn an ERC-721 Token Using Hardhat and Ethers (Part 1)
      • How to Set Access Control, a Token URI, Pause, and Transfer an ERC-721 Token Using Hardhat (Part 2)
      • How to Upgrade an ERC-721 Token with OpenZeppelin UUPS Proxies and Hardhat (Part 3)
      • How to Verify a Smart Contract on HashScan
      • Deploy a Smart Contract Using Remix
      • Deploy a Smart Contract Using Hardhat and Hiero JSON-RPC Relay
      • Deploy Your First Smart Contract
      • Deploy a Contract Using the Hedera Token Service
      • Send and Receive HBAR Using Solidity Smart Contracts
      • Deploy By Leveraging Ethereum Developer Tools On Hedera
      • Deploy a Subgraph Using The Graph and Hedera JSON-RPC Relay
      • Deploy Smart Contracts on Hedera Using Truffle
      • The Power of Native Hedera Tokens as ERC-20 Tokens: A step-by-step guide
      • HTS x EVM - Part 1: How to Mint NFTs
      • HTS x EVM - Part 2: KYC & Update
      • HTS x EVM - Part 3: How to Pause, Freeze, Wipe, and Delete NFTs
      • Hedera Smart Contracts Workshop
        • Setup
        • Solidity
        • Hedera SDK JS
        • Hardhat and EthersJs
        • Outro
      • Foundry
        • How to Setup Foundry and Write a Basic Unit Test
        • How to Deploy and Verify a Hedera Smart Contract with Foundry
        • How to Test A Solidity Event
        • How to Fork Testnet on Latest Block
    • Consensus
      • Submit Your First Message
      • Submit Message to Private Topic
      • Query Messages with Mirror Node
    • Tokens
      • Create and Transfer Your First NFT
      • Create and Transfer Your First Fungible Token
      • Create and Transfer an NFT using a Solidity Contract
      • Structure Your Token Metadata Using JSON Schema V2
      • Hedera Token Service - Part 1: How to Mint NFTs
      • Hedera Token Service - Part 2: KYC, Update, and Scheduled Transactions
      • Hedera Token Service - Part 3: How to Pause, Freeze, Wipe, and Delete NFTs
      • Create Your First Frictionless Airdrop Campaign
    • Local Node
      • How to Run Hedera Local Node in a Cloud Development Environment (CDE)
        • Run a Local Node in Gitpod
        • Run a Local Node in Codespaces
      • How to Set Up a Hedera Local Node
      • Set Up a Hedera Local Node using the NPM CLI
    • More Tutorials
      • Create and Fund Your Hedera Testnet Account
      • How to Create a Personal Access Token (API Key) on the Hedera Portal
      • How to Auto-Create Hedera Accounts with HBAR and Token Transfers
      • How to Configure a Mirror Node and Query Data
      • How to Generate a Random Number on Hedera
      • Get Started with the Hedera Consensus Service Fabric Plugin
        • Virtual Environment Setup
      • Schedule Your First Transaction
      • How to Connect to Hedera Networks Over RPC
        • Configuring Hashio RPC endpoints
        • Configuring Hiero JSON-RPC Relay endpoints
        • Configuring Validation Cloud RPC endpoints
      • JavaScript Testing
      • Create a Hedera DApp Integrated with WalletConnect
      • How to Connect MetaMask to Hedera
    • Demo Applications
    • Starter Projects
    • Building on Hedera (course)
  • Networks
    • Mainnet
      • Mainnet Accounts
      • Mainnet Consensus Nodes
        • Node Requirements
          • FAQ
      • Fees
        • Transaction Records
    • Testnets
      • Testnet Accounts
      • Testnet Consensus Nodes
    • Localnet
      • Single Node Configuration
      • Multinode Configuration
    • Network Explorers and Tools
    • Release Notes
      • Consensus Node
      • Hedera Mirror Node
  • Core Concepts
    • Accounts
      • Account Creation
      • Auto Account Creation
      • Account Properties
    • Keys and Signatures
    • Schedule Transaction
    • Smart Contracts
      • Understanding Hedera's EVM Differences and Compatibility
        • For EVM Developers Migrating to Hedera
          • Accounts, Signature Verification & Keys (ECDSA vs. ED25519)
          • JSON-RPC Relay and EVM Tooling
          • Token Management with Hedera Token Service
          • Decimal Handling (8 vs. 18 Decimals)
          • Handling HBAR Transfers in Contracts
        • For Hedera-Native Developers Adding Smart Contract Functionality
          • Integrating ED25519 Accounts and Advanced Features Into Smart Contracts
          • JSON-RPC Relay and State Queries
          • Extending Token Management with Smart Contracts
      • Creating Smart Contracts
      • Compiling Smart Contracts
      • System Smart Contracts
        • Hedera Account Service
        • Hedera Schedule Service
      • Gas and Fees
      • JSON-RPC Relay
      • Deploying Smart Contracts
      • Smart Contract Addresses
      • Verifying Smart Contracts
      • Smart Contract Traceability
      • Tokens Managed by Smart Contracts
        • ERC-20 (Fungible Tokens)
        • ERC-721 (Non-Fungible Token)
        • ERC-3643 Real World Assets (RWA)
        • ERC-1363 (Payable Tokens)
        • Hedera Token Service System Contract
      • Wrapped HBAR (WHBAR)
      • Smart Contract Rent
      • Smart Contract Security
      • EVM Archive Node Queries
    • Tokens
      • Tokenization on Hedera
      • Hedera Token Service (HTS) Native Tokenization
        • Token Types and ID Formats
        • Token Properties
        • Token Creation
        • Custom Fee Schedule
        • Token Airdrops
      • ERC/EVM-Compatible Tokenization
      • Hybrid (HTS + EVM ) Tokenization
    • Staking
      • Staking Program
      • Stake HBAR
    • Hashgraph Consensus Algorithm
      • Gossip About Gossip
      • Virtual Voting
    • Transactions and Queries
      • Transaction Properties
    • State and History
    • Mirror Nodes
      • Hedera Mirror Node
      • One Click Mirror Node Deployment
      • Run Your Own Mirror Node
        • Run Your Own Mirror Node with Google Cloud Storage (GCS)
        • Run Your Mirror Node with Amazon Web Services S3 (AWS)
  • Open Source Solutions and Integrations
    • AI Studio on Hedera
      • ElizaOS Plugin for Hedera
      • Hedera AI Agent Kit
      • MCP Server
      • OpenConvAI
    • AI Tools for Developers
      • Hedera Hivemind
      • Kapa AI
    • Asset Tokenization Studio (ATS)
      • Web User Interface (UI)
      • Frequently Asked Questions (FAQs)
    • HashioDAO
      • Governance Token DAO
      • NFT DAO
      • Multisig DAO
      • DAO Proposals
      • Local Environment Setup
    • Hedera CLI
    • Hedera Contract Builder
    • Hedera Custodians Library
      • How to use it
    • Hedera Developers Code Repository
    • Hedera Developer Playground
    • Hedera Wallet Snap By MetaMask
      • Hedera Wallet Snap Documentation
      • Tutorial: MetaMask Snaps – What Are They and How to Use Them
    • Interoperability and Bridging
      • LayerZero
    • NFT Studio
      • Airdrop List Verifier
      • Metadata Validator
      • NFT Rarity Inspector
      • NFT Token Holders List Builder
      • NFT Risk Calculator
      • Token Balance Snapshot
      • Hedera NFT SDK
    • Oracle Networks
      • Chainlink Oracles
      • Pyth Oracles
      • Supra Oracles
    • Stablecoin Studio
      • Core Concepts
      • Web UI Application
      • CLI Management
      • TypeScript SDK
    • Hedera Guardian
    • Hedera WalletConnect
  • SDKs & APIs
    • SDKs
      • Build Your Hedera Client
      • Set Up Your Local Network
      • Network Address Book
      • Keys
        • Generate a new key pair
        • Import an existing key
        • Create a key list
        • Create a threshold key
        • Generate a mnemonic phrase
        • Recover keys from a mnemonic phrase
      • HBAR
      • Specialized Types
      • Pseudorandom Number Generator
      • Transactions
        • Create a Batch Transaction
        • Transaction ID
        • Modify transaction fields
        • Create an unsigned transaction
        • Manually sign a transaction
        • Submit a transaction
        • Sign a multisignature transaction
        • Get a transaction receipt
        • Get a transaction record
      • Schedule Transaction
        • Schedule ID
        • Create a schedule transaction
        • Sign a scheduled transaction
        • Delete a schedule transaction
        • Get schedule info
        • Network Response Messages
      • Queries
      • General Network Response Messages
      • Accounts and HBAR
        • Create an account
        • Update an account
        • Transfer cryptocurrency
        • Approve an allowance
        • Delete an allowance
        • Delete an account
        • Get account balance
        • Get account info
        • Network Response Messages
      • Consensus Service
        • Create a topic
        • Update a topic
        • Submit a message
        • Delete a topic
        • Get topic messages
        • Get topic info
        • Network Response
      • Token Service
        • Token ID
        • NFT ID
        • Token types
        • Create a token
        • Custom token fees
        • Update a token
        • Update token custom fees
        • Update NFT metadata
        • Transfer tokens
        • Airdrop a token
        • Claim a token
        • Cancel a token
        • Reject a token
        • Delete a token
        • Mint a token
        • Burn a token
        • Freeze an account
        • Unfreeze an account
        • Enable KYC account flag
        • Disable KYC account flag
        • Associate tokens to an account
        • Dissociate tokens from an account
        • Pause a token
        • Unpause a token
        • Wipe a token
        • Atomic swaps
        • Get account token balance
        • Get token info
        • Get NFT info
        • Network Response Messages
      • File Service
        • Create a file
        • Append to a file
        • Update a file
        • Delete a file
        • Get file contents
        • Get file info
        • Network Response Messages
      • Smart Contract Service
        • Delegate Contract ID
        • Create a smart contract
        • Update a smart contract
        • Delete a smart contract
        • Call a smart contract function
        • Ethereum transaction
        • Get a smart contract function
        • Get smart contract bytecode
        • Get smart contract info
        • Hedera Service Solidity Libraries
        • Network Response Messages
      • Signature Provider
        • Provider
        • Signer
        • Wallet
        • Local Provider
    • Mirror Node REST API
      • Accounts
      • Balances
      • Blocks
      • Schedule Transactions
      • Smart Contracts
      • Tokens
      • Topics
      • Transactions
      • Network
    • Hedera Consensus Service gRPC API
    • Hedera APIs
      • Basic Types
        • AccountAmount
        • AccountID
        • ContractID
        • CryptoAllowance
        • CurrentAndNextFeeSchedule
        • FeeComponents
        • FeeData
        • FeeSchedule
        • FileID
        • Fraction
        • HederaFunctionality
        • Key
        • KeyList
        • NftAllowance
        • NftTransfer
        • NodeAddress
        • NodeAddressBook
        • RealmID
        • ScheduleID
        • SemanticVersion
        • ServicesConfigurationList
        • ServiceEndpoint
        • Setting
        • ShardID
        • Signature
        • SignatureList
        • SignatureMap
        • SignaturePair
        • SubType
        • TransferList
        • TransactionID
        • ThresholdKey
        • ThresholdSignature
        • TokenAllowance
        • TokenBalance
        • TokenBalances
        • TokenFreezeStatus
        • TokenPauseStatus
        • TokenID
        • TokenKycStatus
        • TokenRelationship
        • TokenTransferList
        • TokenType
        • TokenSupplyType
        • TopicID
        • TransactionFeeSchedule
      • Cryptocurrency Accounts
        • CryptoService
        • CryptApproveAllowance
        • CryptoDeleteAllowance
        • CryptoCreate
        • CryptoTransfer
        • CryptoUpdate
        • CryptoDelete
        • CryptoGetAccountBalance
        • CryptoGetAccountRecords
        • CryptoGetInfo
        • CryptoGetStakers
      • Consensus Service
        • Consensus Service
        • ConsensusCreateTopic
        • ConsensusUpdateTopic
        • ConsensusSubmitMessage
        • ConsensusDeleteTopic
        • ConsensusTopicInfo
        • ConsensusGetTopicInfo
      • Schedule Service
        • ScheduleService
        • SchedulableTransactionBody
        • ScheduleCreate
        • ScheduleDelete
        • ScheduleSign
        • ScheduleGetInfo
      • Token Service
        • TokenService
        • CustomFees
          • AssessedCustomFee
          • CustomFee
          • FractionalFee
          • FixedFee
          • RoyaltyFee
        • TokenCreate
        • TokenUpdate
        • TokenFeeScheduleUpdate
        • TokenDelete
        • TokenMint
        • TokenBurn
        • TokenFreezeAccount
        • TokenUnfreezeAccount
        • TokenGrantKyc
        • TokenRevokeKyc
        • TokenAssociate
        • TokenDissociate
        • TokenWipeAccount
        • TokenPause
        • TokenUnpause
        • TokenGetInfo
        • TokenGetNftInfo
        • TokenGetNftInfos
        • TokenGetAccountNftInfo
      • File Service
        • FileService
        • FileCreate
        • FileAppend
        • FileUpdate
        • FileDelete
        • FileGetContents
        • FileGetInfo
      • Smart Contracts
        • SmartContractService
        • ContractCall
        • ContractCallLocal
        • ContractCreate
        • ContractUpdate
        • ContractDelete
        • ContractGetByteCode
        • ContractGetInfo
        • ContractGetRecords
      • Miscellaneous
        • Duration
        • ExchangeRate
        • Freeze
        • FreezeType
        • GetByKey
        • GetBySolidityID
        • NetworkGetVersionInfo
        • NetworkService
        • Query
        • QueryHeader
        • Response
        • ResponseCode
        • ResponseHeader
        • SystemDelete
        • SystemUndelete
        • TimeStamp
        • Transaction
        • TransactionBody
        • TransactionContents
        • TransactionGetFastRecord
        • TransactionGetReceipt
        • TransactionGetRecord
        • TransactionReceipt
        • TransactionRecord
        • TransactionResponse
        • UncheckedSubmit
    • Hedera Status API
  • Support & Community
    • Glossary
    • Contributing to Hedera documentation
      • Contribution Guidelines
        • Creating Issues
        • Creating Pull Requests
        • Hedera Improvement Proposal (HIP)
        • Submit Demo Applications
      • Style Guide
        • Understanding different types of documentation
        • Use of HBAR and tinybars
        • Use of web2 and web3
        • Language and grammar
        • Formatting
        • Punctuation
        • GitBook Markdown Syntax
    • Discord
    • GitHub
    • Stack Overflow
    • Hedera Blog
    • Bug Bounty
    • Hedera Help
    • Documentation Survey
    • Meetups
    • Brand Guidelines
    • Status Page
Powered by GitBook
LogoLogo

INTRODUCTION

  • Fees
  • Core Concepts
  • Network Information

TOOLS

  • Bridge
  • Oracles
  • Explorers
  • Developer Portal & Faucet

RESOURCES

  • Status
  • Bug Bounty
  • Build on Hedera (course)
  • Documentation Survey
On this page
  • Summary
  • Prerequisites
  • Table of Contents
  • How do you connect metadata to a token?
  • What does the Token Metadata JSON schema V2 look like?
  • Required fields:
  • Optional fields:
  • Putting things together:
  • How do you verify your token metadata is correct?
  • Want to learn more about token metadata?

Was this helpful?

Edit on GitHub
  1. Tutorials
  2. Tokens

Structure Your Token Metadata Using JSON Schema V2

PreviousCreate and Transfer an NFT using a Solidity ContractNextHedera Token Service - Part 1: How to Mint NFTs

Last updated 2 months ago

Was this helpful?

Summary

When you create a new fungible or non-fungible token, you have the ability to add metadata. It's common to add metadata for NFTs, but also fungible tokens. The biggest problem with metadata is that it's often unstructured or doesn't follow a set of guidelines.

Therefore, Hedera has developed the " for developers and creators who want to structure their metadata in an organized way. The biggest benefit of using this community-accepted standard is that most of the tooling on the Hedera network can scrape and interpret your metadata, like NFT explorers listing rarity attributes based on your metadata.


Prerequisites

We recommend you complete one of the two tutorials below that teach you how to create a fungible or non-fungible token on the Hedera network.


Table of Contents


How do you connect metadata to a token?

It's essential to understand that the token metadata JSON schema V2 requires you to store metadata using a storage solution, centralized or decentralized, such as IPFS or Arweave.

When creating a non-fungible token using the Hedera Token Service, you set the metadata value to the metadata JSON file to define your NFT, wherever it’s stored. This technique allows you to connect the metadata to the token created on the Hedera network. The "memo" or "symbol" fields are not allowed on the NFT.

// IPFS content identifier (CID) that points to your metadata
String CID = ("QmTzWcVfk88JRqjTpVwHzBeULRTNzHY7mnBSG42CpwHmPa") ;

// Mint a new NFT
TokenMintTransaction mintTx = new TokenMintTransaction()
        .setTokenId(tokenId)
        .addMetadata(CID.getBytes())
	.freezeWith(client);
// IPFS content identifier (CID) that points to your metadata
let CID = "ipfs://QmTzWcVfk88JRqjTpVwHzBeULRTNzHY7mnBSG42CpwHmPa";

// Mint new NFT
let mintTx = await new TokenMintTransaction()
    .setTokenId(tokenId)
    .setMetadata([Buffer.from(CID)])
    .freezeWith(client);
// IPFS content identifier (CID) that points to your metadata
CID := "QmTzWcVfk88JRqjTpVwHzBeULRTNzHY7mnBSG42CpwHmPa"

//Mint new NFT
mintTx, err := hedera.NewTokenMintTransaction().
	SetTokenID(tokenId).
	SetMetadata([]byte(CID)).
	FreezeWith(client)

What does the Token Metadata JSON schema V2 look like?

First of all, you can find the full reference implementation of this JSON schema here:

  • IPFS: ipfs://bafkreidcsqzr5su356thecwuyzrhsgekfdsqzuyuqxtsu4vh7oc34iv5oy

Let's take a look at the different fields you can specify.

Required fields:

The schema defines three required fields:

  • name: Full name of the NFT

  • image: A URI pointing to an image (decentralized or centralized storage).

The image field can both serve as a preview or full-resolution image for your NFT to ensure cross-platform compatibility. The image field will be displayed in wallets and marketplaces by default.

Creators are recommended to point to a thumbnail in the image field and put the high-resolution image in the files array with the is_default_file boolean set to indicate that this file represents the default image for the NFT. (This is shown in the next section)

Here's a small example of an implementation.

{
    "name": "My first NFT",
    "type": "image/png",
    "image": "https://myserver.com/preview-image-nft-001.png"
}

Optional fields:

The files field represents an array containing file objects. For collectible NFTs, the files array allows you to store the high-resolution image of your NFT. However, you can also use this field for multi-file NFTs. Each file object requires a URI and type.

It's recommended to use the is_default_file field to indicate which file is the main file for your NFT. Besides that, the files array allows you to upload or link file-specific metadata. This allows you to nest files indefinitely.

{
    "name": "My first NFT",
    "type": "image/png",
    "image": "https://myserver.com/preview-image-nft-001.png",
    "files": [
        {
            "uri": "https://myserver.com/high-resolution-nft-001.png",
            "checksum": "9defbb6402d4bf39f2ea580099c73194647b24a659b6f6b778e3dd71755b8862",
            "is_default_file": true,
            "type": "image/png"
        }
    ]
}

Additional fields are not allowed to be defined at the root level of the metadata object.

// ❌ Not allowed to add "website" to the root of the object
{
    "website": "https://mysite.com",
    "name": "My first NFT",
    "type": "image/png",
    "image": "https://myserver.com/preview-image-nft-001.png"
}

If you want to add custom fields, you can add them to the properties object. For example, you are linking to a website or social media pages. You can structure the metadata within the properties field as needed. Some developers even prefer defining their own standard for the properties field, not for the entire metadata object.

// ✅ Good example
{
    "name": "My first NFT",
    "type": "image/png",
    "image": "https://myserver.com/preview-image-nft-001.png",
    "properties": {
        "website": "https://mysite.com",
        "socials": {
            "linkedin": "https://www.linkedin.com/in/myprofile/"
        }
    }
}

The attributes field is specifically used to calculate the rarity of NFTs. It's an industry-accepted way to define traits and their values for a collectible NFT collection in order to calculate the rarity score of the NFT.

The attributes field consists of an array of attribute objects. This is the structure of such an object:

  • trait_type: (required) Name of the trait.

  • value: (required) Value for the trait, e.g., for a trait_type = clothing, values can be pants, shirt, or t-shirt.

  • display_type: (optional) Allows you to specify how the trait should be displayed. For instance, you can set it to datetime so the person or bot knows the value should be interpreted as a date.

  • max_value: (optional) It's possible to set a max_value for a numerical value.

{
    "name": "My first NFT",
    "type": "image/png",
    "image": "https://myserver.com/preview-image-nft-001.png",
    "attributes": [
    	{
    		"trait_type": "clothing",
    		"value": "pants"
    	},
    	{
		"trait_type": "color",
		"display_type": "color",
		"value": "rgb(255,0,0)"
	},
	{
		"trait_type": "hasPipe",
		"display_type": "boolean",
		"value": true
	},
	{
		"trait_type": "coolness",
		"display_type": "boost",
		"value": 10,
		"max_value": 100
	},
	{
		"trait_type": "stamina",
		"display_type": "percentage",
		"value": 83
	},
	{
		"trait_type": "birth",
		"display_type": "datetime",
		"value": 732844800
	}
    ]
}

The standard also allows for localization. Each locale links to another metadata file containing localized metadata and files. This allows for a clean metadata structure. Don't define a new localization object for a localized metadata file to avoid infinite looping when parsing an NFT's metadata file.

{
    "name": "My first NFT",
    "type": "image/png",
    "image": "https://myserver.com/preview-image-nft-001.png",
    "localization": {
        "uri": "ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/{locale}.json",
	"default": "en",
	"locales": ["es", "fr"]
    }
}

In this example, the default locale is set to English (en) and the schema provides localization for Spanish (es) and French (fr). The schema assumes it can find the Spanish and French version under the following URIs because of the way it has been specified using the interpolation notation {locale}.json. This is what the resulting URIs should look like:

ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/es.json
ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/fr.json

A localized file would have the same structure, but doesn't specify any localization field. Here's an example for the French version.

// metadata for ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/fr.json
{
    "name": "Mon NFT (French)",
    "type": "image/png",
    "image": "https://myserver.com/preview-image-nft-001.png"
}

Here's a list of optional fields you can define according to the Token Metadata JSON Schema V2 specification.

  • description: A text that describes your token or NFT collection.

  • creator: Identifies the artist name(s).

  • creatorDID: Points to a decentralized identifier to identify the creator.

  • checksum: Cryptographic SHA-256 hash of the representation of the image resource or resources in the files array. It allows browsers or other tooling to verify the integrity of any file you list.

  • format: Indicates the implemented metadata schema specification. Currently, the default version (Token Metadata JSON Schema V2) is represented by HIP412@2.0.0. If you wonder why, each update to the JSON Schema requires a new Hedera Improvement Proposal (HIP). Therefore, the format field lists the HIP number and the associated version of the Token Metadata JSON Schema.

Putting things together:

This is what a full Token Metadata JSON Schema V2 specification looks like.

{
	"name": "Example NFT 001",
	"creator": "Jane Doe, John Doe",
	"creatorDID": "did:hedera:mainnet:7Prd74ry1Uct87nZqL3ny7aR7Cg46JamVbJgk8azVgUm;hedera:mainnet:fid=0.0.123",
	"description": "This describes my NFT",
	"image": "https://myserver.com/preview-image-nft-001.png",
	"checksum": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
	"type": "image/png",
	"format": "HIP412@2.0.0",
	"properties": {
		"external_url": "https://nft.com/mycollection/001"
	},
	"files": [
		{
			"uri": "https://myserver.com/high-resolution-nft-001.png",
			"checksum": "9defbb6402d4bf39f2ea580099c73194647b24a659b6f6b778e3dd71755b8862",
			"is_default_file": true,
			"type": "image/png"
		},
		{
			"uri": "ipfs://yusopwpksaioposjfopiapnnjlsl",
			"type": "image/png"
		}
	],
	"attributes": [
		{
    			"trait_type": "clothing",
    			"value": "pants"
    		},
		{
			"trait_type": "birth",
			"display_type": "datetime",
			"value": 732844800
		}
	],
	"localization": {
		"uri": "ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/{locale}.json",
		"default": "en",
		"locales": ["es", "fr"]
	}
}

How do you verify your token metadata is correct?

You can install the package using Yarn or NPM.

npm i -s @hashgraph/nft-utilities

Next, you need to import the validator function that accepts your metadata as a JSON object and the schema version against which you want to verify the metadata (2.0.0). Here's the code.

const metadata = {
    attributes: [
        { trait_type: "Background", value: "Yellow" }
    ],
    creator: "NFT artist",
};
const version = '2.0.0';

const issues = validator(metadata, version);
console.log(issues);

The package will return errors and warnings using the below interface. This snippet of example output tells you that you have incorrectly used the percentage display_type in the attributes field, and you have defined a custom field called imagePreview on the root of the metadata object, which is not allowed (use the properties field).

{
    "errors": [
        {
            "type": "attribute",
            "msg": "Trait stamina of type 'percentage' must be between [0-100], found 157",
            "path": "instance.attributes[0]"
        }
    ],
    "warnings": [
        {
            "type": "schema",
            "msg": "is not allowed to have the additional property 'imagePreview'",
            "path": "instance"
        }
    ]
}

Want to learn more about token metadata?

Here's a video about how crucial structuring your token metadata is and how to do it according to Token Metadata JSON Schema V2.

An excerpt from the shows this connection when minting a new NFT.

Hedera Improvement Proposals

type: for the image

Extra resources: You can find all information about the attributes field in the detailed .

Note that the localization.uri property contains {locale}. The {locale} part references a locale in the locales array. You should use two-letter language codes according to the to define languages.

When you create token metadata for the first time, you want to verify your metadata against the Token Metadata JSON Schema V2. To help you, Hedera has created an (only for JavaScript) to verify your metadata against the JSON Schema V2.

You can find examples in this in the section "Token Metadata V2 NFT Examples". If you still have questions, reach out on or ask it on .

Besides that, you can read up on the full implementation of token metadata in the Hedera Improvement Proposals .

NFT minting tutorial
GitHub Repository
NFT.Storage (gateway link)
MIME type
schema specification
ISO 639-1 standard
NFT utilities SDK
blog post
Discord
StackOverflow
GitHub Repository under HIP-412
"Token Metadata JSON Schema V2
Create and Transfer Your First NFT
Create and Transfer Your First Fungible Token
Connect Metadata
Metadata Schema
Verify Metadata
Video Tutorial

Writer: Michiel, Developer Advocate

Editor: Krystal, Technical Writer

|

|

GitHub
LinkedIn
GitHub
Twitter