SNIP-721: Private, Non-Fungible Tokens (NFTs)
SNIP-721 is a specification for private non-fungible tokens based on CosmWasm on the Secret Network. The name and design is loosely based on ERC-721, and is a superset of CosmWasm's CW-721. While this specification is CW-721 compliant, because CW-721 is not capable of privacy, a number of the CW-721-compliant functions may not return all the information a CW-721 implementation would. For example, the OwnerOf query must not display the approvals for a token unless the token owner has supplied his address and viewing key. In order to strive for CW-721 compliance, a number of queries that require authentication use optional parameters that the CW-721 counterpart does not have. If the optional authentication parameters are not supplied, the responses must only display information that the token owner has made public.
The SNIP-721 reference implementation may be used to create SNIP-721-compliant token contracts either as-is or as a base upon which to build additional application-specific functionality.
This specification is split into multiple sections, a contract may only implement some of this functionality, but must implement the base functionality.

Introduction

Scope

This document aims to set standard interfaces that SNIP-721 contract implementors will create, and that both wallet implementors & dependent contract creators will consume. For this reason, the focus of this document is to merely give SNIP-721 contract implementors the tools needed to create contracts that fully maintain privacy but not to specify implementation details. That said, this document may, at times, mention implementation details of the SNIP-721 reference implementation as non-base functionality that developers might choose to mirror.

Terms

  • Message - This is an on-chain interface. It is triggered by sending a transaction, and receiving an on-chain response which is read by the client. Messages are authenticated both by the blockchain, and by the secret enclave.
  • Query - This is an off-chain interface. Queries are done by returning data that a node has locally, and are not public. Query responses are returned immediately, and do not have to wait for blocks.
  • Cosmos Message Sender - The account that is found under the sender field in a standard Cosmos SDK message. This is also the signer of the message.

Memo

Users may want to include private memos with transactions. While it is possible to include a memo with the Cosmos message, that message is publicly viewable. Therefore, to enable private memos, SNIP-721 token contracts must allow an optional memo field in any message that generates a mint, burn, or transfer transaction.

Padding

Users may want to enforce constant length messages to avoid leaking data. To support this functionality, SNIP-721 token contracts must support the option to include a padding field in every message. This optional padding field may be sent with any of the messages in this spec. Contracts must ignore this field if sent.

Requests

Requests should be sent as base64 encoded JSON. Future versions of Secret Network may add support for other formats as well, but at this time we recommend usage of JSON only. For this reason the parameter descriptions specify the JSON type which must be used. In addition, request parameters will include in parentheses a CosmWasm (or other) underlying type that this value must conform to. E.g. a recipient address is sent as a string, but must also be parsed to a bech32 address.

Queries

Queries are off-chain requests that are not cryptographically validated. This means that contracts that wish to validate the caller of a query must implement some sort of authentication. SNIP-721 uses an "API key" scheme, which validates a (viewing key, account) pair.
Authentication must happen on each query that reveals private account-specific information. Authentication must be a resource intensive operation that takes a significant amount of time to compute. This is because such queries are open to offline brute-force attacks, which can be parallelized to scale linearly with the resources of a motivated attacker. Authentication must perform the same computation even if the user does not have a viewing key set. The authentication response must be indistinguishable for both the case of a wrong viewing key and the case of a non-existent viewing key.
One should be aware that the current blockheight and time is not available to a query on Secret Network at this moment, but there are plans to make the BlockInfo available to queries in a future hardfork. To get around this limitation, the SNIP-721 contract may choose to store the BlockInfo every time a message is executed, in order to use the blockheight and time of the last message execution when checking the expiration of an approval during a query. Therefore it is possible that a whitelisted address may be able to view the owner or metadata of a token past its approval expiration if no one executed any contract message since before the expiration.

Responses

Unless otherwise specified, all message & query responses will be JSON encoded in the data field of the Cosmos response, rather than in the logs. This is meant to reduce the potential for data-leakage through side-channel attacks. In addition, since all keys will be encrypted, it is not possible to use the log events for event triggering.

Success status

Some of the messages detailed in this document contain a status field. This field must hold one of two values: "success" or "failure".
While errors during execution of contract functions should usually result in a proper and detailed error response, The "failure" status is reserved for cases where a contract might choose to obfuscate the exact cause of failure, or otherwise indicate that while nothing failed to happen, the operation itself could not be completed for some valid reason.

Base

This handles ownership, transfers, approvals, and metadata. These messages and queries must be consistently supported by all SNIP-721 contracts; however, all metadata response fields are optional to allow for SNIP-721 contracts that choose not to implement metadata. Note that all tokens must have an owner as well as an ID. The ID is an arbitrary string, unique within the contract.

Messages

TransferNft

TransferNft is used to transfer ownership of the token to the recipient address. This requires a valid token_id and the message sender must either be the owner or an address with valid transfer approval. If the token is transferred to a new owner, its single-token approvals must be cleared.
Request
{
"transfer_nft": {
"recipient": "address_receiving_the_token",
"token_id": "ID_of_the_token_being_transferred",
"memo": "optional_memo_for_the_transfer_tx",
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
recipient
string (HumanAddr)
Address receiving the token
no
token_id
string
Identifier of the token to be transferred
no
memo
string
memo for the transfer transaction that is only viewable by addresses involved in the transfer (recipient, sender, previous owner)
yes
nothing
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"transfer_nft": {
"status": "success"
}
}

SendNft

SendNft is used to transfer ownership of the token to the contract address, and then call the recipient's BatchReceiveNft (or ReceiveNft, see below) if the recipient contract has registered its receiver interface with the NFT contract or if its ReceiverInfo is provided. While SendNft keeps the contract field name in order to maintain CW-721 compliance, Secret Network does not have the same limitations as Cosmos, and it is possible to use SendNft to transfer token ownership to a personal address (not a contract) or to a contract that does not implement any Receiver Interface.
SendNft requires a valid token_id and the message sender must either be the owner or an address with valid transfer approval. If the token is transferred to a new owner, its single-token approvals must be cleared. If the BatchReceiveNft (or ReceiveNft) callback fails, the entire transaction must be reverted (even the transfer must not take place).
Request
{
"send_nft": {
"contract": "address_receiving_the_token",
"receiver_info": {
"recipient_code_hash": "code_hash_of_the_recipient_contract",
"also_implements_batch_receive_nft": true | false,
},
"token_id": "ID_of_the_token_being_transferred",
"msg": "optional_base64_encoded_Binary_message_sent_with_the_BatchReceiveNft_callback",
"memo": "optional_memo_for_the_transfer_tx",
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
contract
string (HumanAddr)
Address receiving the token
no
receiver_info
Code hash and BatchReceiveNft implementation status of the recipient contract
yes
nothing
token_id
string
Identifier of the token to be transferred
no
msg
string (base64 encoded Binary)
msg included when calling the recipient contract's BatchReceiveNft (or ReceiveNft)
yes
nothing
memo
string
memo for the tx that is only viewable by addresses involved (recipient, sender, previous owner)
yes
nothing
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"send_nft": {
"status": "success"
}
}

ReceiverInfo

The optional ReceiverInfo object may be used to provide the code hash of the contract receiving tokens from either SendNft or BatchSendNft. It may also optionally indicate whether the recipient contract implements BatchReceiveNft in addition to ReceiveNft. If the also_implements_batch_receive_nft field is not provided, it defaults to false.
{
"recipient_code_hash": "code_hash_of_the_recipient_contract",
"also_implements_batch_receive_nft": true | false,
}
Name
Type
Description
Optional
Value If Omitted
recipient_code_hash
string
Code hash of the recipient contract
no
also_implements_batch_receive_nft
bool
True if the recipient contract implements BatchReceiveNft in addition to ReceiveNft
yes
false

Approve

Approve is used to grant an address permission to transfer a single token. This can only be performed by the token's owner or, in compliance with CW-721, an address that has inventory-wide approval to transfer the owner's tokens. Approve is provided to maintain compliance with CW-721, but the owner can use SetWhitelistedApproval to accomplish the same thing if specifying a token_id and approve_token AccessLevel for transfer.
Request
{
"approve": {
"spender": "address_being_granted_approval_to_transfer_the_specified_token",
"token_id": "ID_of_the_token_that_can_now_be_transferred_by_the_spender",
"expires": "never" | {"at_height": 999999} | {"at_time":999999},
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
spender
string (HumanAddr)
Address being granted approval to transfer the token
no
token_id
string
ID of the token that the spender can now transfer
no
expires
The expiration of this token transfer approval. Can be a blockheight, time, or never
yes
"never"
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"approve": {
"status": "success"
}
}
Expiration
The Expiration object is used to set an expiration for any approvals granted in the message. Expiration can be set to a specified blockheight, a time in seconds since epoch 01/01/1970, or "never". Values for blockheight and time are specified as a u64. If no expiration is given, it must default to "never".
Also, because the current blockheight and time will not be available to queries until a future hardfork makes that possible, please see above regarding an imprecise, and possibly delayed way to enforce expirations on queries in the meantime. This imprecise method must only be applied when checking an expiration during a query. When checking an expiration during a message, the blockheight and time are available and exact expiration must be enforced.
  • "never" - the approval will never expire
  • {"at_time": 1700000000} - the approval will expire 1700000000 seconds after 01/01/1970 (time value is u64)
  • {"at_height": 3000000} - the approval will expire at blockheight 3000000 (height value is u64)

Revoke

Revoke is used to revoke from an address the permission to transfer this single token. This can only be performed by the token's owner or, in compliance with CW-721, an address that has inventory-wide approval to transfer the owner's tokens (referred to as an operator later). However, one operator may not revoke transfer permission of even one single token away from another operator. Revoke is provided to maintain compliance with CW-721, but the owner can use SetWhitelistedApproval to accomplish the same thing if specifying a token_id and revoke_token AccessLevel for transfer.
Request
{
"revoke": {
"spender": "address_being_revoked_approval_to_transfer_the_specified_token",
"token_id": "ID_of_the_token_that_can_no_longer_be_transferred_by_the_spender",
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
spender
string (HumanAddr)
Address no longer permitted to transfer the token
no
token_id
string
ID of the token that the spender can no longer transfer
no
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"revoke": {
"status": "success"
}
}

ApproveAll

ApproveAll is used to grant an address permission to transfer all the tokens in the message sender's inventory. This must include the ability to transfer any tokens the sender acquires after granting this inventory-wide approval. This also gives the address the ability to grant another address the approval to transfer a single token. ApproveAll is provided to maintain compliance with CW-721, but the message sender can use SetWhitelistedApproval to accomplish the same thing by using all AccessLevel for transfer.
Request
{
"approve_all": {
"operator": "address_being_granted_inventory-wide_approval_to_transfer_tokens",
"expires": "never" | {"at_height": 999999} | {"at_time":999999},
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
operator
string (HumanAddr)
Address being granted approval to transfer all of the message sender's tokens
no
expires
The expiration of this inventory-wide transfer approval. Can be a blockheight, time, or never
yes
"never"
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"approve_all": {
"status": "success"
}
}

RevokeAll

RevokeAll is used to revoke all transfer approvals granted to an address. RevokeAll is provided to maintain compliance with CW-721, but the message sender can use SetWhitelistedApproval to accomplish the same thing by using none AccessLevel for transfer.
Request
{
"revoke_all": {
"operator": "address_being_revoked_all_approvals_to_transfer_tokens",
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
operator
string (HumanAddr)
Address being revoked all approvals to transfer the message sender's tokens
no
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"revoke_all": {
"status": "success"
}
}

SetWhitelistedApproval

The owner of a token can use SetWhitelistedApproval to grant an address permission to view ownership, view private metadata, and/or to transfer a single token or every token in the owner's inventory. SetWhitelistedApproval can also be used to revoke any approval previously granted to the address.
Request
{
"set_whitelisted_approval": {
"address": "address_being_granted_or_revoked_approval",
"token_id": "optional_ID_of_the_token_to_grant_or_revoke_approval_on",
"view_owner": "approve_token" | "all" | "revoke_token" | "none",
"view_private_metadata": "approve_token" | "all" | "revoke_token" | "none",
"transfer": "approve_token" | "all" | "revoke_token" | "none",
"expires": "never" | {"at_height": 999999} | {"at_time":999999},
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
address
string (HumanAddr)
Address to grant or revoke approval to/from
no
token_id
string
If supplying either approve_token or revoke_token access, the token whose privacy is being set
yes
nothing
view_owner
Grant or revoke the address' permission to view the ownership of a token/inventory
yes
nothing
view_private_metadata
Grant or revoke the address' permission to view the private metadata of a token/inventory
yes
nothing
transfer
Grant or revoke the address' permission to transfer a token/inventory
yes
nothing
expires
The expiration of any approval granted in this message. Can be a blockheight, time, or never
yes
"never"
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"set_whitelisted_approval": {
"status": "success"
}
}
AccessLevel
AccessLevel determines the type of access being granted or revoked to the specified address in a SetWhitelistedApproval message or to everyone in a SetGlobalApproval message. Inventory-wide approval and token-specific approval are mutually exclusive levels of access. The levels are:
  • "approve_token" - grant approval only on the token specified in the message
  • "revoke_token" - revoke a previous approval on the specified token
  • "all" - grant approval for all tokens in the message signer's inventory. This approval must also apply to any tokens the signer acquires after granting all approval
  • "none" - revoke any approval (both token and inventory-wide) previously granted to the specified address (or for everyone if using SetGlobalApproval)

RegisterReceiveNft

A contract will use RegisterReceiveNft to notify the SNIP-721 contract that it implements ReceiveNft and possibly also BatchReceiveNft (see below). This enables the SNIP-721 contract to call the registered contract whenever it is Sent a token (or tokens). In order to comply with CW-721, ReceiveNft only informs the recipient contract that it has been sent a single token, and it only informs the recipient contract who the token's previous owner was, not who sent the token (which may be different addresses) despite calling the previous owner sender (see below). BatchReceiveNft, on the other hand, can be used to inform a contract that it was sent multiple tokens, and notifies the recipient of both, the token's previous owner and the sender.
Request
{
"register_receive_nft": {
"code_hash": "code_hash_of_the_contract_implementing_a_receiver_interface",
"also_implements_batch_receive_nft": true | false,
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
code_hash
string
A 32-byte hex encoded string, with the code hash of the message sender, which is a contract that implements a receiver
no
also_implements_batch_receive_nft
bool
true if the message sender contract also implements BatchReceiveNft so it can be informed that it was sent a list of tokens
yes
false
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"register_receive_nft": {
"status": "success"
}
}

CreateViewingKey

CreateViewingKey generates a new viewing key for the Cosmos message sender, which is used to authenticate account-specific queries, because queries in Cosmos have no way to cryptographically authenticate the querier's identity.
The Viewing Key must be implemented in such a way that validation takes a significant amount to time to perform, in order to be resistant to brute-force attacks. The viewing key must only be used to authenticate queries, as messages cryptographically authenticate the sender.
The entropy field of the request should be a client supplied string used for entropy for generation of the viewing key. Secure implementation is left to the contract developer, but it is recommended to use base-64 encoded random bytes and not predictable inputs.
Request
{
"create_viewing_key": {
"entropy": "string_used_as_part_of_the_entropy_supplied_to_the_rng",
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
entropy
string
String used as part of the entropy supplied to the rng that generates the random viewing key
no
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"viewing_key": {
"key": "the_created_viewing_key"
}
}

SetViewingKey

SetViewingKey is used to set the viewing key to a predefined string. It must replace any key that currently exists. It would be best for users to call CreateViewingKey to ensure a strong key, but this function is provided so that contracts can also utilize viewing keys.
Request
{
"set_viewing_key": {
"key": "the_new_viewing_key",
"padding": "optional_ignored_string_that_can_be_used_to_maintain_constant_message_length"
}
}
Name
Type
Description
Optional
Value If Omitted
key
string
The new viewing key for the message sender
no
padding
string
An ignored string that can be used to maintain constant message length
yes
nothing
Response
{
"viewing_key": {
"key": "the_message_sender's_viewing_key"
}
}

Queries

ContractInfo

ContractInfo returns the contract's name and symbol. This query is not authenticated.
Request
{
"contract_info": {}
}
Response
{
"contract_info": {
"name": "contract_name",
"symbol": "contract_symbol"
}
}

NumTokens

NumTokens returns the number of tokens controlled by the contract. If the contract's token supply is private, the SNIP-721 contract may choose to only allow an authenticated minter's address to perform this query.
Request
{
"num_tokens": {
"viewer": {
"address": "address_of_the_querier_if_supplying_optional_ViewerInfo",
"viewing_key": "viewer's_key_if_supplying_optional_ViewerInfo"
}
}
}
Name
Type
Description
Optional
Value If Omitted
viewer
The address and viewing key performing this query
yes
nothing
Response
{
"num_tokens": {
"count": 99999
}
}
Name
Type
Description
Optional
count
number (u32)
Number of tokens controlled by this contract
no
ViewerInfo
The ViewerInfo object provides the address and viewing key of the querier. It is optionally provided in queries where public responses and address-specific responses will differ.
{
"address": "address_of_the_querier_if_supplying_optional_ViewerInfo",
"viewing_key": "viewer's_key_if_supplying_optional_ViewerInfo"
}
Name
Type
Description
Optional
Value If Omitted
address
string (HumanAddr)
Address performing the query
no
viewing_key
string
The querying address' viewing key
no

OwnerOf

OwnerOf returns the owner of the specified token if the querier is the owner or has been granted permission to view the owner. If the querier is the owner, OwnerOf must also display all the addresses that have been given transfer permission. The transfer approval list is provided as part of CW-721 compliance; however, the token owner is advised to use NftDossier (see below) for a more complete list that includes view_owner and view_private_metadata approvals (which CW-721 is not capable of keeping private). If no viewer is provided, OwnerOf must only display the owner if ownership is public for this token.
Request
{
"owner_of": {
"token_id": "ID_of_the_token_being_queried",
"viewer": {
"address": "address_of_the_querier_if_supplying_optional_ViewerInfo",
"viewing_key": "viewer's_key_if_supplying_optional_ViewerInfo"
},
"include_expired": true | false
}
}
Name
Type
Description
Optional
Value If Omitted
token_id
string
ID of the token being queried
no
viewer
The address and viewing key performing this query
yes
nothing
include_expired
bool
True if expired transfer approvals should be included in the response
yes
false
Response
{
"owner_of": {
"owner": "address_of_the_token_owner",
"approvals": [
{
"spender": "address_with_transfer_approval",
"expires": "never" | {"at_height": 999999} | {"at_time":999999}
},
{
"...": "..."
}
]
}
}
Name
Type
Description
Optional
owner
string (HumanAddr)
Address of the token's owner
no
approvals
List of approvals to transfer this token
no
Cw721Approval
The Cw721Approval object is used to display CW-721-style approvals which are limited to only permission to transfer, as CW-721 does not enable ownership or metadata privacy.
{
"spender": "address_with_transfer_approval",
"expires": "never" | {"at_height": 999999} | {"at_time":999999}
}
Name
Type
Description
Optional
spender
string (HumanAddr)
Address whitelisted to transfer a token
no
expires
The expiration of this transfer approval. Can be a blockheight, time, or never
no

NftInfo

NftInfo returns the public metadata of a token. All metadata fields are optional to allow for SNIP-721 contracts that choose not to implement metadata, but at most, one of the fields token_uri OR extension should be defined. Metadata follows CW-721 specification, which is based on ERC-721 Metadata JSON Schema.
Request
{
"nft_info": {
"token_id": "ID_of_the_token_being_queried"
}
}
Name
Type
Description
Optional
Value If Omitted
token_id
string
ID of the token being queried
no
Response
{
"nft_info": {
"token_uri": "optional_uri_pointing_to_off-chain_JSON_metadata",
"extension": {
"...": "..."
}
}
Name
Type
Description
Optional
token_uri
string
Uri pointing to off-chain JSON metadata
yes
extension
Data structure defining on-chain metadata
yes
At most, one of the fields token_uri OR extension should be defined.
Metadata
This is the metadata for a token that follows CW-721 metadata specification, which is based on ERC721 Metadata JSON Schema. At most, one of the fields token_uri OR extension should be defined.
{
"token_uri": "optional_uri_pointing_to_off-chain_JSON_metadata",
"extension": {
"...": "..."
}
}
Name
Type
Description
Optional
Value If Omitted
token_uri
string
Uri pointing to off-chain JSON metadata
yes
nothing
extension
Data structure defining on-chain metadata
yes
nothing
At most, one of the fields token_uri OR extension should be defined.
Extension
Extension can be any data structure representing token metadata that is stored on-chain. See here for the description of the Extension that the reference implementation uses.

AllNftInfo

AllNftInfo displays the result of both OwnerOf and NftInfo in a single query. This is provided for CW-721 compliance, but for more complete information about a token, use NftDossier, which will include private metadata and view_owner and view_private_metadata approvals if the querier is permitted to view this information.
Request
{
"all_nft_info": {
"token_id": "ID_of_the_token_being_queried",
"viewer": {
"address": "address_of_the_querier_if_supplying_optional_ViewerInfo",
"viewing_key": "viewer's_key_if_supplying_optional_ViewerInfo"
},
"include_expired": true | false
}
}
Name
Type
Description
Optional
Value If Omitted
token_id
string
ID of the token being queried
no
viewer
The address and viewing key performing this query
yes
nothing
include_expired
bool
True if expired transfer approvals should be included in the response
yes
false
Response
{
"all_nft_info": {
"access": {
"owner": "address_of_the_token_owner",
"approvals": [
{
"spender": "address_with_transfer_approval",
"expires": "never" | {"at_height": 999999} | {"at_time":999999}
},
{
"...": "..."
}
]
},
"info": {
"token_uri": "optional_uri_pointing_to_off-chain_JSON_metadata",
"extension": {
"...": "..."
}
}
}
}
Name
Type
Description
Optional
access
The token's owner and its transfer approvals if permitted to view this info
no
info
The token's public metadata
yes
Cw721OwnerOfResponse
The Cw721OwnerOfResponse object is used to display a token's owner if the querier has view_owner permission, and the token's transfer approvals if the querier is the token's owner.
{
"owner": "address_of_the_token_owner",
"approvals": [
{
"spender": "address_with_transfer_approval",
"expires": "never" | {"at_height": 999999} | {"at_time":999999}
},
{
"...": "..."
}
]
}
Name
Type
Description
Optional
owner
string (HumanAddr)
Address of the token's owner
yes
approvals
List of approvals to transfer this token
no

PrivateMetadata

PrivateMetadata returns the private metadata of a token if the querier is permitted to view it. All metadata fields are optional to allow for SNIP-721 contracts that choose not to implement private metadata, but at most, one of the fields token_uri OR extension should be defined. Metadata follows CW-721 metadata specification, which is based on ERC-721 Metadata JSON Schema. If no viewer is provided, PrivateMetadata must only display the private metadata if the private metadata is public for this token.
Request
{
"private_metadata": {
"token_id": "ID_of_the_token_being_queried",
"viewer": {
"address": "address_of_the_querier_if_supplying_optional_ViewerInfo",
"viewing_key": "viewer's_key_if_supplying_optional_ViewerInfo"
},
}
}
Name
Type
Description
Optional
Value If Omitted
token_id
string
ID of the token being queried
no
viewer
The address and viewing key performing this query
yes
nothing
Response
{
"private_metadata": {
"token_uri": "optional_uri_pointing_to_off-chain_JSON_metadata",
"extension": {
"...": "..."
}
}
}
Name
Type
Description
Optional
token_uri
string
Uri pointing to off-chain JSON metadata
yes
extension
Data structure defining on-chain metadata
yes
At most, one of the fields token_uri OR extension should be defined.

NftDossier

NftDossier returns all the information about a token that the viewer is permitted to view. If no viewer is provided, NftDossier will only display the information that has been made public. The response may include the owner, the public metadata, the private metadata, the reason the private metadata is not viewable, the royalty information, the mint run information, whether ownership is public, whether the private metadata is public, and (if the querier is the owner,) the approvals for this token as well as the inventory-wide approvals for the owner. The implementation may choose to hide royalty recipient addresses. See here for a description of how the reference implementation determines who is permitted to view royalty recipient addresses.
Request
{
"nft_dossier": {
"token_id": "ID_of_the_token_being_queried",
"viewer": {
"address": "address_of_the_querier_if_supplying_optional_ViewerInfo",
"viewing_key": "viewer's_key_if_supplying_optional_ViewerInfo"
},
"include_expired": true | false
}
}
Name
Type
Description
Optional
Value If Omitted
token_id
string
ID of the token being queried
no
viewer
The address and viewing key performing this query
yes
nothing
include_expired
bool
True if expired approvals should be included in the response
yes
false
Response
{
"nft_dossier": {
"owner": "address_of_the_token_owner",
"public_metadata": {
"token_uri": "optional_uri_pointing_to_off-chain_JSON_metadata",
"extension": {
"...": "..."
}
},
"private_metadata": {
"token_uri": "optional_uri_pointing_to_off-chain_JSON_metadata",
"extension": {
"...": "..."
}
},
"display_private_metadata_error": "optional_error_describing_why_private_metadata_is_not_viewable_if_applicable",
"royalty_info": {
"decimal_places_in_rates": 4,
"royalties": [
{
"recipient": "optional_address_that_should_be_paid_this_royalty",
"rate": 100,
},
{
"...": "..."
}
],
},
"mint_run_info": {
"collection_creator": "optional_address_that_instantiated_this_contract",
"token_creator": "optional_address_that_minted_this_token",
"time_of_minting": 999999,
"mint_run": 3,
"serial_number": 67,
"quantity_minted_this_run": 1000,
},
"owner_is_public": true | false,
"public_ownership_expiration": "never" | {"at_height": 999999} | {"at_time":999999},
"private_metadata_is_public": true | false,
"private_metadata_is_public_expiration": "never" | {"at_height": 999999} | {"at_time":999999},
"token_approvals": [
{
"address": "whitelisted_address",
"view_owner_expiration": "never" | {"at_height": 999999} | {"at_time":999999},
"view_private_metadata_expiration": "never" | {"at_height": 999999} | {"at_time":999999},
"transfer_expiration": "never" | {"at_height": 999999} | {"at_time":999999},
},
{
"...": "..."
}
],
"inventory_approvals": [
{
"address": "whitelisted_address",
"view_owner_expiration": "never" | {"at_height": 999999} | {"at_time":999999},
"view_private_metadata_expiration": "never" | {"at_height": 999999} | {"at_time":999999},
"transfer_expiration": "never" | {"at_height": 999999} | {"at_time":999999},
},
{
"...": "..."
}
]
}
}
Name
Type
Description
Optional
owner
string (HumanAddr)
Address of the token's owner
yes
public_metadata
The token's public metadata
yes
private_metadata
The token's private metadata
yes
display_private_metadata_error
string
If the private metadata is not displayed, the corresponding error message
yes
royalty_info
The token's RoyaltyInfo
yes
mint_run_info
The token's MintRunInfo
yes
owner_is_public
bool
True if ownership is public for this token
no
public_ownership_expiration
When public ownership expires for this token. Can be a blockheight, time, or never
yes
private_metadata_is_public
bool
True if private metadata is public for this token
no
private_metadata_is_public_expiration
When public display of private metadata expires. Can be a blockheight, time, or never
yes
token_approvals
List of approvals for this token
yes
inventory_approvals