Structure Your Token Metadata Using JSON Schema V2

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 "Token Metadata JSON Schema V2" 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.

Create and Transfer Your First NFTCreate and Transfer Your First Fungible Token

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.

An excerpt from the NFT minting tutorial shows this connection when minting a new 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);

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:

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

  • type: MIME type for the image

  • 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"
        }
    ]
}

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?

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 NFT utilities SDK (only for JavaScript) to verify your metadata against the JSON Schema V2.

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.

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

Besides that, you can read up on the full implementation of token metadata in the Hedera Improvement Proposals GitHub Repository under HIP-412.

Last updated