Metadata standards
Overview
Using asset metadata, Mavis Market can incorporate rich data for your NFTs and display it on the collection page and the token details page. Because digital assets on smart contracts are usually represented by nothing but a unique identifier, such as tokenId
in ERC-721, metadata plays a crucial role in enhancing these tokens with additional properties, which includes a name, description, image, and some custom attributes.
How to implement token URI
Metadata is stored off-chain.
In order for Mavis Market to pull it for your ERC-721 and ERC-1155 assets, your contract needs to return a URI where our system can find the metadata.
To identify this URI, we use the tokenURI
function in ERC-721 and the uri
function in ERC-1155.
Whichever standard you follow, the function in your contract should return an HTTP or IPFS URL.
When our system queries it, the URL should return a JSON blob of data with the metadata for your token.
Metadata structure
Mavis Market supports metadata that is structured according to the official ERC-721 metadata standard or the Enjin Metadata suggestions.
We also support other properties such as images, videos, and animation, as well as interactive traits for your items, which enables sorting and filtering capabilities on the collection page.
The following example shows metadata for one of the assets on Mavis Market:
{
"name": "Carota",
"description": "Carota",
"image": "https://cdn.skymavis.com/mm-cache/5/f/6139f745ad89731b16844a4fee546c.gif",
"animation_url": "https://viewer.cyberkongz.com/4570.html",
"attributes": [ ... ]
}
The following table defines each property:
Property | Required? | Description |
---|---|---|
name | Required | The name of the item. |
description | Optional | A human-readable description of the item. |
image | Required | A URL to an image of the item. This image is displayed on the collection page and token detail page if the video and animation_url properties are empty. Supports PNG, JPEG, and GIF formats. Use at least a 480x480-pixel attachment with the size of up to 1 MB. Regardless the resolution, Mavis Market caches and downscales your images to 480x480 pixels. |
video | Optional | A URL to a video of the item. This video is displayed on the details page. Supports MP4 and WEBM formats. Use at least a 480x480-pixel video with the size of up to 1 MB. Host the video on a CDN instead of directly on the server, otherwise the load speed may be slow. Note: To prevent issues with video display, share the CDN URL with your Sky Mavis point of contact so we can allowlist it. |
external_url | Optional | A URL to an item's webpage on your site. Note: This property is not yet live on Mavis Market, so we store the URL internally until further notice. |
attributes | Optional | One of the two ways to store attributes for an item, mutually exclusive with properties . We recommend that you use this property for your NFT metadata, because this enables better sorting and filtering on the collection page, and allows using specific display types for your traits. |
properties | Optional | One of the two ways to store attributes for an item, mutually exclusive with attributes . Doesn't support specific display types for your traits, which may limit the filtering experience on the collection page. |
animation_url | Optional | A URL to an HTML page with any rich media content, such as an interactive animation of the item. This attachment is displayed on the token details page. For more details, see an example video. Note: Share the domain name with your Sky Mavis point of contact so we can allowlist it. |
Metadata display priority
- On the collection page: the
image
is displayed. - On the token details page:
animation_url
>video
>image
. - If the
animation_url
andvideo
are empty, theimage
is displayed on the collection page and the token details page.
If you use a GIF attachment, fill it in the image
property, not in the animation_url
property.
Attributes
You can add custom attributes to your metadata that appears underneath each item. There are two ways to store custom attributes: using an attributes
array or a properties
object.
- If you store your custom metadata in the
attributes
array, you can set the display type for traits, such asstring
,number
,date
, andbool
. This affects how the trait is displayed on the marketplace. - If you store metadata in the
properties
object, you can use numeric and string values, but Mavis Market will display all your NFT traits as strings. - Use either an
attributes
array or aproperties
object, not both at the same time.
Note: Mavis Market ignores any attributes with incorrect value types. For example, if you define display_type
as number
, but pass a string in value
, the attribute is ignored.
The following image shows one of the Mavis Market items that uses attributes for custom metadata:
To generate these attributes, we stored them in the following way:
{
"name": "Mavis #0001",
"description": "Step into the world of birds and join Mavis.",
"external_url": "https://marketplace.skymavis.com/mavis/birdDetail/?birdId=0001",
"image": "https://marketplace.skymavis.com/birds/Mavis_0_1.jpg",
"attributes": [
{
"display_type": "string",
"trait_type": "Planet Class",
"value": "the fury"
},
{
"display_type": "string",
"trait_type": "Planet Type",
"value": "forestry"
},
{
"display_type": "number",
"trait_type": "Conjunction Count",
"value": 2
},
{
"display_type": "date",
"trait_type": "Born Time",
"value": 1679938000
},
{
"display_type": "number",
"trait_type": "Element-Air",
"value": 42
},
{
"display_type": "number",
"trait_type": "Element-Earth",
"value": 31
},
{
"display_type": "number",
"trait_type": "Element-Fire",
"value": 0
},
{
"display_type": "number",
"trait_type": "Element-Water",
"value": 27
},
{
"display_type": "string",
"trait_type": "Bloodline",
"value": "tri"
},
{
"display_type": "number",
"trait_type": "Generation",
"value": 1
}
]
}
About the use of nested attributes
When structuring your metadata, place all traits combined on the root level of the attributes
key or properties
key, depending on the convention that you use.
Recommended:
"attributes": [
{
"display_type": "number",
"trait_type": "Level",
"value": 3
},
{
"display_type": "string",
"trait_type": "Hat",
"value": "Blue Bandana"
},
Not recommended:
"attributes": {
"nested_attributes": [
{
"display_type": "number",
"trait_type": "Level",
"value": 3
},
{
"display_type": "string",
"trait_type": "Hat",
"value": "Blue Bandana"
},
In the preceding example, the trait_type
is the trait's name, the value
is the value of the trait, and the display_type
is a field indicating how you want the trait to be displayed on Mavis Market. The system calculates the distribution of each trait type’s value automatically, so you don't need to specify it in the metadata, unless it's required for your own logic.
When parsing your NFT metadata, Mavis Market specifically looks for the data stored in the trait_type
, value
, and display_type
keys. Data stored in any other keys is disregarded.
If you store metadata in the properties
object, you can use numeric and string values, but Mavis Market displays all your NFT traits as strings.
{
"name": "Mavis #0001",
"description": "Step into the world of birds and join Mavis.",
"image": "https://marketplace.skymavis.com/birds/Mavis_0_1.jpg",
"properties": {
"Planet Class": "the fury",
"Planet Type": "forestry",
"Conjunction Count": 2,
"Born Time": 1679938000,
"Element-Air": 42,
"Element-Earth": 31,
"Element-Fire": 0,
"Element-Water": 27,
"Bloodline": "tri",
"Generation": 1
}
}
String traits
For string traits, Mavis Market supports a string
display type. When adding string traits, you don't need to explicitly state a display_type
, but you need to enclose the value in quotes and keep the attributes human-readable.
Use either this:
{
"trait_type": "Planet Class",
"value": "the fury"
},
Or this:
{
"display_type": "string",
"trait_type": "Planet Class",
"value": "the fury"
},
The following image shows string traits on the token details page:
Bool traits
For "true" or "false" traits, Mavis Market supports a bool
display type:
{
"display_type": "bool",
"trait_type": "Protected",
"value": true
}
The following image shows a filter for "true" or "false" traits on the collection page:
Numeric traits
For numeric traits, Mavis Market supports a number
display type. You can specify a pair of min and max values or just a single value. The max_value
parameter is optional, it sets a ceiling for the possible values for a numeric trait. It defaults to the maximum value that Mavis Market has seen so far on the items in your contract. If you set a max_value
, make sure that it doesn’t exceed the value
.
When defining numeric traits, format the values as either floats or integers.
{
"display_type": "number",
"trait_type": "Element-Earth",
"value": 18
},
{
"display_type": "number",
"trait_type": "Element-Fire",
"value": 24
},
{
"display_type": "number",
"trait_type": "Element-Water",
"value": 29
}
The following image shows numeric traits with max values on the token details page:
While the following images shows a filter for numeric traits on the collection page:
Date traits
For dates, Mavis Market supports a date
display type. Pass in a Unix timestamp in seconds as the value.
{
"display_type": "date",
"trait_type": "Created Date",
"value": 1701167938
},
{
"display_type": "date",
"trait_type": "Expiration Date",
"value": 1732703938
},
The following image shows date traits on the token details page:
While the following image illustrates a filter for dates on the collection page:
Trait grouping
Mavis Market offers an optional capability to group your NFT traits into different categories and display them in a pre-defined order on the token details page. This feature is useful when you have a large number of traits and want to organize them in a more structured way.
Custom trait grouping
Key things to know when defining custom trait groups:
- All traits are placed in the "Properties" section on the token details page.
- If a trait type isn't found in any group, it's placed in the "Others" category within the "Properties" section.
- The name of each trait in the grouping array must match the
trait_type
in theattributes
array of your NFT's metadata. - A trait type can belong to only one trait group. If you add a trait type to more than one group, Mavis Market selects its first occurrence.
The following image shows how Mavis Market displays traits with custom grouping:
The JSON file used to define the custom grouping looks like this:
{
"name": "About",
"traits": [ {"name": "Planet Class"}, {"name": "Planet Type"}, {"name": "Conjunction Count"}, {"name": "Born Time"} ]
},
{
"name": "Element's Value",
"traits": [ {"name": "Element-Air"}, {"name": "Element-Earth"}, {"name": "Element-Fire"}, {"name": "Element-Water"} ]
}
To define trait groups for your assets, create a JSON array in the following format and submit it as part of your collection's information:
[
{
"name": "<YOUR FIRST GROUP>",
"traits": [
{
"name": "<FIRST GROUP - FIRST TRAIT>"
},
{
"name": "<FIRST GROUP - SECOND TRAIT>"
},
{
"name": "<FIRST GROUP - THIRD TRAIT>"
},
{
"name": "<FIRST GROUP - FORTH TRAIT>"
}
]
},
{
"name": "<YOUR SECOND GROUP>",
"traits": [
{
"name": "<SECOND GROUP - FIRST TRAIT>"
},
{
"name": "<SECOND GROUP - SECOND TRAIT>"
}
]
},
...
]
Default trait grouping
If you don't provide any custom grouping, Mavis Market still places all traits in the "Properties" section on the token details page. Within that section, the traits are further organized as follows:
- Any strings, dates, and boolean trait types are placed in the "Traits" category and sorted alphabetically.
- Any numeric trait types are added to the "Others" category, also sorted alphabetically.
The following image shows how Mavis Market displays traits without custom grouping:
Metadata deployment
You can deploy your metadata any way you see fit: host it on IPFS, cloud storage, or your own servers.
Refrain from using bot prevention on the server where you host your metadata. Mavis Market relies on fetching metadata from the server to index data and allow searching across the collection.
Metadata refresh
To refresh token metadata on Mavis Market, you can use one of the following methods:
Emit on-chain events
Emit on-chain events as defined in ERC-4906:
event MetadataUpdate(uint256 _tokenId);
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
To refresh an entire collection, emit a _toTokenId
with the type(uint256).max
.
GraphQL API
Make a request to the Mavis Market GraphQL API.
Example request:
curl 'https://marketplace-graphql.skymavis.com/graphql' \
-H 'content-type: application/json' \
--data-raw $'{"operationName":"RefreshMetadata","variables":{"tokenAddress":"0x1f7c16fce4fc894143afb5545bf04f676bf7dcf3","tokenId":"6545"},"query":"mutation RefreshMetadata($tokenAddress: String\u0021, $tokenId: String\u0021) {\\n refreshMetadata(tokenAddress: $tokenAddress, tokenId: $tokenId)\\n}\\n"}' \
--compressed
REST API
Make a request to the Refresh NFT metadata endpoint to refresh the metadata of up to 100 tokens at a time.
Example request:
curl --location --request POST 'https://api-gateway.skymavis.com/mavis-market-partner/collections/0xa899849929e113315200609be208e6a0858f645c/refresh_metadata' \
--header 'Content-Type: application/json' \
--header 'X-API-Key: YOUR_API_KEY' \
--data-raw '{
"token_ids": ["1", "2", "3", "4", "5", "6"]
}'
If your new metadata alters the display_type
of the existing trait_type
, inform your Sky Mavis point of contact to perform the update.
Disable trading for staked or locked tokens
Mavis Market prevents trading of staked or locked NFTs by tracking events emitted by the NFT smart contract. This mechanism ensures users cannot list, transfer, or trade tokens that are currently locked, reducing the risk of errors or unintended actions.
The supported events are as follows:
event TokenLocked(uint256 indexed tokenId, address indexed approvedContract);
event TokenUnlocked(uint256 indexed tokenId, address indexed approvedContract);
The approvedContract
is an optional tracker that identifies the contract initiating the lock or unlock action. While not mandatory for logic enforcement, it provides additional transparency for monitoring or debugging.
The lock status of an NFT is determined by its lock count:
- If the lock count is greater than 0, the NFT is considered locked, and trading actions are disabled.
- If the lock count is 0, the NFT is unlocked, and trading is re-enabled.