Skip to content

Token Metadata

Sequence provides a metadata service for fetching token metadata for any ERC721 or ERC1155 contract, on any EVM chain.

Fetch token metadata for any ERC721 or ERC1155 contract

Sequence Metadata GetTokenMetadata Method:

  • Request: POST /rpc/Metadata/GetTokenMetadata
  • Content-Type: application/json
  • Body (in JSON):
    • chainID (string) -- the chain id, as a name or number (ie. "1" or "mainnet", "137" or "polygon", etc.)
    • contractAddress (string) -- the contract address
    • tokenIDs (array of strings) -- array of strings containing token ids to fetch metadata

Example: GetTokenMetadata of some tokens using an c3bgcU3LkFR9Bp9jFssLenPAAAAAAAAAA
cURL
curl -X POST -H "Content-Type: application/json" -H "X-Access-Key: c3bgcU3LkFR9Bp9jFssLenPAAAAAAAAAA" https://metadata.sequence.app/rpc/Metadata/GetTokenMetadata -d '{"chainID":"polygon", "contractAddress": "0x631998e91476DA5B870D741192fc5Cbc55F5a52E", "tokenIDs": ["65537", "65538", "65539"] }'

Refreshing token metadata

When deploying new contracts or metadata updates the refresh token metadata url should be called with an access key from (the Sequence Builder) via a HTTPS POST request by command line or via metadata SDK in a program for data to indexeable in the Sequence Indexer metadata service.

Sequence Metadata enqueueTokensForRefresh Method:

  • Request: POST /rpc/Metadata/EnqueueTokensForRefresh
  • Content-Type: application/json
  • Body (in JSON):
    • chainID (string) -- the chain id, as a name or number (ie. "1" or "mainnet", "137" or "polygon", etc.)
    • contractAddress (string) -- the contract address
    • tokenIDs (array of strings) -- array of strings containing token ids to fetch metadata
cURL
curl -v -X POST -H "Content-type: application/json" -H "X-Access-Key: wuELppeX0pttvJABl8bIuxPAAAAAAAAAA" https://metadata.sequence.app/rpc/Metadata/EnqueueTokensForRefresh -d '{"chainID":"polygon", "contractAddress":"0x631998e91476DA5B870D741192fc5Cbc55F5a52E", "tokenIDs": ["1","2"]}'

Sequence Metadata getTokenRefreshStatus Method:

  • Request: POST /rpc/Metadata/GetTokenRefreshStatus
  • Content-Type: application/json
  • Body (in JSON):
    • taskId (uint) -- the task id returned from enqueueTokensForRefresh
cURL
curl -v -X POST -H "Content-type: application/json" -H "X-Access-Key: wuELppeX0pttvJABl8bIuxPAAAAAAAAAA" https://metadata.sequence.app/rpc/Metadata/GetTokenRefreshStatus -d '{"taskId": 1234}'

Testing instructions:

  1. Check current token metadata using token metadata fetch
  2. Modify token metadata content either onchain or via token baseURI
  3. Call refresh token ID endpoints using refresh metadata
  4. Check token metadata changes using token metadata fetch

Token Metadata Standards

Popular token standards like EIP721 and EIP1155 both have similar metadata standard formats with some subtle differences. In addition to the standards, we've seen in practice that projects often slightly deviate from the standards but are sensical, easy to parse and well supported in the ecosystem, include the Sequence Metadata service. Below we describe the standards and common practices across projects to help demystify how to format your token metadata for your projects.

Metadata Standards

ERC721

ERC721 token contracts contain a method on the contract called tokenURI(uint256) string. When querying the tokenURI method on the contract, it will return a URI which contains additional metadata for that asset.

See EIP for specific details: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md

Here is an example Bored Ape (token id 9)

response:

{
  "tokenId": "9",
  "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
  "name": "",
  "description": "",
  "image": "https://ipfs.sequence.info/ipfs/QmUQgKka8EW7exiUHnMwZ4UoXA11wV7NFjHAogVAbasSYy",
  "decimals": 0,
  "properties": null,
  "attributes": [
    {
      "trait_type": "Earring",
      "value": "Silver Stud"
    },
    {
      "trait_type": "Eyes",
      "value": "Sleepy"
    },
    {
      "trait_type": "Mouth",
      "value": "Small Grin"
    },
    {
      "trait_type": "Fur",
      "value": "Brown"
    },
    {
      "trait_type": "Hat",
      "value": "Seaman's Hat"
    },
    {
      "trait_type": "Clothes",
      "value": "Stunt Jacket"
    },
    {
      "trait_type": "Background",
      "value": "Purple"
    }
  ]
}

In the case of this Bored Ape, it appears there is no name or description set, but they do have "attributes" as an array of { "trait_type": string, "value: string }.

Additionally, see OpenSea for more information: https://docs.opensea.io/docs/metadata-standards

Note that OpenSea technically breaks the ERC1155 standard by suggesting to use "attributes", where in fact, the ERC1155 calls uses the field name "properties" instead of "attributes", see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md#erc-1155-metadata-uri-json-schema (read section below). However this is completely okay and mixed use of properties / attributes is compatible in practice. On Sequence Metadata, we support both structures for token contracts which use either format for their properties/attributes.

Another example is from Neon District

ERC1155

ERC1155 token contracts contain a method on the contract called uri(uint256) string. When querying the uri method on the contract, it will return a URI which contains additional metadata for that asset.

See EIP for specific details: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md#erc-1155-metadata-uri-json-schema

Here is an example Skyweaver card (token id 65548)

{
  "tokenId": "65548",
  "contractAddress": "0x27a11c1563a5dda238379b95c91b3abbad9c0cf6",
  "name": "Weighted Die (Silver)",
  "description": "Give +1/+1, armor, and guard to a random ally unit, six times.\n\n\"I will not bow to fate. If the dice fall against me, I'll cut off the hand that cast them.\"\n -Horik",
  "image": "https://assets.skyweaver.net/LV7xNcQh/webapp/cards/full-cards/6x/12-silver.png",
  "decimals": 2,
  "properties": {
    "artists": {
      "name": "Artist",
      "value": [
        {
          "id": "xavi",
          "name": "Henrique Xavier",
          "url": "https://www.artstation.com/kitexavier"
        }
      ]
    },
    "baseCardId": 12,
    "cardType": "Spell",
    "element": "Metal",
    "mana": 8,
    "prism": "Strength",
    "type": "Silver"
  },
  "attributes": null
}

As you can see, Skyweaver an ERC1155 token's metadata uses the properties object, which is an object/dictionary type of arbitrary data.

Attributes vs Properties

As you can see, the standard format of token metadata contains both attributes and properties. The attributes field is an array of objects. The properties field is an object/dictionary of arbitrary data. In technical terms, the attributes type is defined as []map<string,any> and the properties type is defined as map<string,any>.

In practice, we've seen that many projects use both attributes and properties to store the same data, and in some cases, they use attributes to store data that should be in properties and vice versa. Sometimes project use both fields, and this is completely fine in practice, as marketplaces and services will parse both areas.

Finally, if you are looking to extend the metadata format to suit your project, we recommend to utilize either or both the attributes and properties fields for either ERC721 or ERC1155.

ERC20

Finally, a note on ERC20 tokens. ERC20 tokens are just a single token, so they themselves do not have a token ID, but are represented entirely by their contract address. We can infer some information about the token by querying the contract methods such as name and decimals. Additionally, ERC20 tokens can take advantage of the contractURI extension used by OpenSea and described in more detail in our Contract metadata section.