In this tutorial, we will demonstrate how to retrieve data for an NFT collection from Ethereum, Binance Smart Chain (BSC), or any blockchain compatible with the Ethereum Virtual Machine (EVM).
This tutorial was originally published on Bitquery Community. Please check out original post: NFT API - Complete Guide
To get started for free, please create an account with your email: GraphQL IDE .Once you create the account, check out our docs to learn how to create your first query.
To learn more about how to use the Bitquery API, please see the following resources:
- Historical / Near-Realtime Chain Data: Blockchain API Documentation (V1 Graphql Docs) | Blockchain Graphql API (V1 API Docs)
- Realtime Data , Websocket and Cloud Product: Blockchain Streaming API (V2 Graphql Docs) | Streaming API (V2 API Docs)
To get ownership of an NFT token, we need to provide its token address and ID of the specific NFT. It will provide all the owners if we don’t provide limit
 and orderBy
. By providing this field, we are getting the latest owner of the NFT.
This API uses the BalanceUpdates
 method, which tracks all balance updates. Additionally, you can get similar results using the Transfers API.
query MyQuery {
EVM(dataset: combined, network: eth) {
BalanceUpdates(
where: {BalanceUpdate: {Id: {eq: "9990"}}, Currency: {SmartContract: {is: "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e"}}}
limit: {count: 10}
orderBy: {descendingByField: "Balance"}
) {
BalanceUpdate {
Address
}
Balance: sum(of:BalanceUpdate_Amount, selectWhere:{gt:"0"})
}
}
}
To get the top holders of an NFT we provide the NFT address in the Currency SmartContract
 field. We limit the list to 10 owners ordered by the balance
.
query MyQuery {
EVM(dataset: combined, network: eth) {
BalanceUpdates(
orderBy: {descendingByField: "Balance"}
limit: {count: 10}
where: {Currency: {SmartContract: {is: "0x7dD4F223D9155F412790D696Fa30923489d4Ad34"}}}
) {
BalanceUpdate {
Address
}
Balance: sum(of: BalanceUpdate_Amount, selectWhere: {gt: "0"})
}
}
}
The following query provides the daily NFT transfers using the Transfers API.
{
EVM(dataset: combined network: eth){
Transfers(
orderBy: {descendingByField: "count"}
limit: {offset: 10 count: 0}
where: {
Block: {Date: {since: "2023-05-02" till: "2023-05-09" }}
Transfer: {Currency: {Fungible: false}}}
){
Transfer {
Currency {
Symbol
SmartContract
}
}
count
senders: uniq(of: Transfer_Sender method: approximate)
receivers: uniq(of: Transfer_Receiver method: approximate)
ids: uniq(of: Transfer_Id method: approximate)
}
}
}
To get the latest transfers, we will provide the NFT token contract address; if you want to track the transfer of a specific NFT, then you can also provide the ID
 of the NFT with the token address.
{
EVM(dataset: archive, network: eth) {
Transfers(
where: {Transfer: {Currency: {SmartContract: {is: "0xdba45c28b32f2750bdc3c25d6a0118d8e1c8ca80"}}}}
limit: {count: 10}
orderBy: {descending: Block_Time}
) {
Transfer {
Amount
Currency {
Name
Symbol
}
Receiver
Sender
Type
Id
URI
Data
}
}
}
}
To get the latest NFT transfers of a user, you can use Transfers APIs; in the following API, we are getting all transfers where the user is the sender and where the user is the receiver.
You can also get transfers of more than 1 user by using in: []
 operators instead of is: {}
{
EVM(dataset: archive, network: eth) {
sent: Transfers(
where: {Transfer: {Sender: {is: "0x415bdfed5a7c490e1a89332648d8eb339d4eea69"}}}
limit: {count: 10}
orderBy: {descending: Block_Time}
) {
Transfer {
Amount
Currency {
Name
Symbol
}
Receiver
Sender
Type
Id
URI
}
}
recieved: Transfers(
where: {Transfer: {Receiver: {is: "0x415bdfed5a7c490e1a89332648d8eb339d4eea69"}}}
limit: {count: 10}
orderBy: {descending: Block_Time}
) {
Transfer {
Amount
Currency {
Name
Symbol
}
Receiver
Sender
Type
Id
URI
}
}
}
}
Using our Streaming APIs, you can also subscribe to changes on blockchains. We use a GrpahQL subscription, which is similar to WebSockets. For example, in the following API, we are subscribing to the latest transfers of 0xdba45c28b32f2750bdc3c25d6a0118d8e1c8ca80 NFT token.
subscription {
EVM(network: eth, trigger_on: head) {
Transfers(
where: {Transfer: {Currency: {SmartContract: {is: "0xdba45c28b32f2750bdc3c25d6a0118d8e1c8ca80"}}}}
limit: {count: 10}
orderBy: {descending: Block_Time}
) {
Transfer {
Amount
Currency {
Name
Symbol
}
Receiver
Sender
Type
Id
URI
Data
}
}
}
}
To check the latest Smart contract calls made on NFT token contracts, you can use our smartContractCalls
API.
{
EVM {
Calls(
limit: {count: 10}
orderBy: {descending: Block_Time}
where: {Call: {To: {is: "0x60e4d786628fea6478f785a6d7e704777c86a7c6"}}}
) {
Call {
From
Gas
GasUsed
To
Value
}
Transaction {
Hash
}
Arguments {
Name
Value {
... on EVM_ABI_Integer_Value_Arg {
integer
}
... on EVM_ABI_String_Value_Arg {
string
}
... on EVM_ABI_Address_Value_Arg {
address
}
... on EVM_ABI_BigInt_Value_Arg {
bigInteger
}
... on EVM_ABI_Bytes_Value_Arg {
hex
}
... on EVM_ABI_Boolean_Value_Arg {
bool
}
}
}
}
}
}
In the following query, we are getting the latest Opensea trades by tracking the Seaport protocol (Here seaport_v1.4 means all versions of seaport) and all transactions sent to Opensea’s seaport contract 0x00000000000000adc04c56bf30ac9d3c0aaf14dc
.
query MyQuery {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {Trade: {Dex: {ProtocolName: {in: "seaport_v1.4"}}}, Transaction: {To: {is: "0x00000000000000adc04c56bf30ac9d3c0aaf14dc"}}}
limit: {count: 10}
) {
Trade {
Buy {
Currency {
Name
ProtocolName
Symbol
Fungible
SmartContract
}
Amount
Buyer
Ids
Price
URIs
}
Sell {
Currency {
Name
ProtocolName
Symbol
Decimals
Fungible
SmartContract
}
Amount
Buyer
Ids
URIs
}
}
}
}
}
We can aggregate trading vol, trade count, buyer, seller, and nfts and sort them based on trade count in the following query to get the most traded NFT on OpenSea.
query MyQuery {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {Trade: {Dex: {ProtocolName: {in: "seaport_v1.4"}}}, Transaction: {To: {is: "0x00000000000000adc04c56bf30ac9d3c0aaf14dc"}}}
orderBy: {descendingByField: "count"}
limit: {count: 10}
) {
tradeVol: sum(of: Trade_Buy_Amount)
count
buyers: count(distinct: Trade_Buy_Buyer)
seller: count(distinct: Trade_Buy_Seller)
nfts: count(distinct: Trade_Buy_Ids)
Trade {
Buy {
Currency {
Name
ProtocolName
Symbol
Fungible
SmartContract
}
}
}
}
}
}
To get the stats for specific NFT we need to add the currency contract address in the above query. For example, check the query below.
query MyQuery {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {Trade: {Dex: {ProtocolName: {in: "seaport_v1.4"}}, Buy: {Currency: {Fungible: false}}}, Transaction: {To: {is: "0x00000000000000adc04c56bf30ac9d3c0aaf14dc"}}}
orderBy: {descendingByField: "count"}
limit: {count: 10}
) {
tradeVol: sum(of: Trade_Buy_Amount)
count
buyer: count(distinct: Trade_Buy_Buyer)
seller: count(distinct: Trade_Buy_Seller)
nfts: count(distinct: Trade_Buy_Ids)
Trade {
Buy {
Currency {
Name
ProtocolName
Symbol
Fungible
SmartContract
}
}
}
}
}
}
query MyQuery {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {Trade: {Dex: {ProtocolName: {in: "seaport_v1.4"}}, Buy: {Currency: {Fungible: false}}}, Transaction: {To: {is: "0x00000000000000adc04c56bf30ac9d3c0aaf14dc"}}}
orderBy: {descendingByField: "count"}
limit: {count: 10}
) {
count
uniq_tx: count(distinct: Transaction_Hash)
Block {
first_date: Time(minimum: Block_Date)
last_date: Time(maximum: Block_Date)
}
nfts: count(distinct: Trade_Buy_Ids)
difffernt_nfts: count(distinct: Trade_Buy_Currency_SmartContract)
total_money_paid: sum(of: Trade_Sell_Amount)
Trade {
Buy {
Buyer
}
}
}
}
}
In this query, we will get specific buyer stats for a specific NFT on Opensea.
query MyQuery {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {Trade: {Dex: {ProtocolName: {in: "seaport_v1.4"}}, Buy: {Currency: {SmartContract: {is: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"}}, Buyer: {is: "0x2f9ecaa66e12b6168996a6b80cda9bb142f80dd0"}}}, Transaction: {To: {is: "0x00000000000000adc04c56bf30ac9d3c0aaf14dc"}}}
orderBy: {descendingByField: "count"}
limit: {count: 10}
) {
count
uniq_tx: count(distinct: Transaction_Hash)
Block {
first_date: Time(minimum: Block_Date)
last_date: Time(maximum: Block_Date)
}
nfts: count(distinct: Trade_Buy_Ids)
Trade {
Buy {
Buyer
Currency {
Name
ProtocolName
Symbol
Fungible
SmartContract
}
}
}
}
}
}
In the following query, we are getting all NFT trades for Seaport v1.4
 protocol. Many marketplaces utilize the Seaport protocol; we can add a Smart contract in Trade → Dex → SmartContract to get a specific marketplace for this protocol.
query MyQuery {
EVM {
DEXTrades(
limit: {offset: 0, count: 10}
orderBy: {descendingByField: "Block_Time"}
where: {Trade: {Dex: {ProtocolName: {is: "seaport_v1.4"}}}}
) {
Trade {
Dex {
ProtocolName
}
Buy {
Price
Seller
Buyer
Currency {
HasURI
Name
Fungible
SmartContract
}
}
Sell {
Price
Amount
Currency {
Name
}
Buyer
Seller
}
}
Transaction {
Hash
}
Block {
Time
}
}
}
}
In the following query, we are getting the latest NFT trades of an address.
query MyQuery {
EVM(dataset: combined) {
DEXTrades(
limit: {offset: 0, count: 10}
orderBy: {descendingByField: "Block_Time"}
where: {Trade: {Buy: {Buyer: {is: "0x6afdf83501af209d2455e49ed9179c209852a701"}, Currency: {Fungible: false}}}}
) {
Trade {
Dex {
ProtocolName
OwnerAddress
Delegated
DelegatedTo
ProtocolName
SmartContract
}
Buy {
Price
Seller
Buyer
Currency {
Symbol
HasURI
Name
Fungible
SmartContract
}
Ids
OrderId
URIs
}
Sell {
Price
Amount
Currency {
Name
}
Buyer
Seller
}
}
Transaction {
Hash
}
Block {
Time
}
}
}
}
Let’s get the most traded NFTs of the month using the following query.
{
EVM(dataset: combined, network: eth) {
DEXTrades(
orderBy: {descendingByField: "count"}
limit: {offset: 0, count: 10}
where: {Block: {Date: {since: "2023-05-01", till: "2023-05-28"}}, Trade: {Buy: {Currency: {Fungible: false}}, Sell: {Currency: {Fungible: true}}}}
) {
Trade {
Buy {
Currency {
Symbol
SmartContract
}
min_price: Price(minimum: Trade_Buy_Price)
max_rice: Price(maximum: Trade_Buy_Price)
}
Sell {
Currency {
Symbol
SmartContract
}
}
}
buy_amount: sum(of: Trade_Buy_Amount)
sell_amount: sum(of: Trade_Sell_Amount)
count
}
}
}
We will use the current dataset (with endpoint -Â https://graphql.bitquery.io/
) to get the address that created the transaction which created the contract 0x6339e5E072086621540D0362C4e3Cea0d643E114
{
ethereum {
smartContractCalls(
options: {desc: "block.height", limit: 100, offset: 0}
smartContractMethod: {is: "Contract Creation"}
smartContractAddress: {is: "0x6339e5E072086621540D0362C4e3Cea0d643E114"}
) {
block {
height
timestamp {
time
}
}
creator: caller {
address
annotation
}
transaction {
hash
}
smartContract {
contractType
address {
address
annotation
}
currency {
name
symbol
decimals
tokenType
}
}
}
}
}
{
EVM(dataset: archive, network: eth) {
Transfers(
where: {Transfer: {Currency: {SmartContract: {is: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"}}, Id: {eq: "4226"}}}
limit: {count: 1, offset: 0}
orderBy: {descending: Block_Number}
) {
Transfer {
Currency {
SmartContract
Name
Decimals
Fungible
HasURI
Symbol
}
Id
URI
Data
owner: Receiver
}
}
}
}
{
EVM(dataset: archive, network: eth) {
Transfers(
where: {Transfer: {Currency: {SmartContract: {is: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"}}}}
limitBy: {by: Transfer_Id, count: 1}
limit: {count: 1000, offset: 0}
orderBy: {descending: Transfer_Id}
) {
Transfer {
Currency {
SmartContract
Name
}
Id
URI
Data
}
}
}
}
{
ethereum {
arguments(
smartContractEvent: {is: "SaleCreatedEvent"}
smartContractAddress: {is: "0xa2707b069EEbca7f8Ae133162f19FE720D3aAA58"}
options: {limit: 100}
) {
block {
height
}
acceptFiat: any(of: argument_value, argument: {is: "acceptFiat"})
priceInWei: any(of: argument_value, argument: {is: "priceInWei"})
tokenId: any(of: argument_value, argument: {is: "tokenId"})
acceptFiat: any(of: argument_value, argument: {is: "acceptFiat"})
tokenContractAddress: any(
of: argument_value
argument: {is: "tokenContractAddress"}
)
transaction {
hash
}
}
}
}
To get the token holders of a collection, we use the BalanceUpdates
 method to query all the addresses that had added the NFT whose SmartContract
 is mentioned in the query. To get more wallets, increase the count
 .
{
EVM(dataset: archive, network: eth) {
BalanceUpdates(
where: {Currency: {SmartContract: {is: "0x23581767a106ae21c074b2276d25e5c3e136a68b"}}}
limitBy: {by: BalanceUpdate_Address, count: 1}
limit: {count: 1000}
orderBy: {descendingByField: "sum"}
) {
sum(of: BalanceUpdate_Amount, selectWhere: {gt: "0"})
BalanceUpdate {
Address
}
}
}
}
Bitquery is your comprehensive toolkit designed with developers in mind, simplifying blockchain data access. Our products offer practical advantages and flexibility.
-
APIs - Explore API: Easily retrieve precise real-time and historical data for over 40 blockchains using GraphQL. Seamlessly integrate blockchain data into your applications, making data-driven decisions effortless.
-
Coinpath® - Try Coinpath: Streamline compliance and crypto investigations by tracing money movements across 40+ blockchains. Gain insights for efficient decision-making.
-
Data in Cloud - Try Demo Bucket: Access indexed blockchain data cost-effectively and at scale for your data pipeline. We currently support Ethereum, BSC, Solana, with more blockchains on the horizon, simplifying your data access.
-
Explorer - Try Explorer: Discover an intuitive platform for exploring data from 40+ blockchains. Visualize data, generate queries, and integrate effortlessly into your applications.
Bitquery empowers developers with straightforward blockchain data tools. If you have questions or need assistance, connect with us on our Telegram channel or via email at hello@bitquery.io. Stay updated on the latest in cryptocurrency by subscribing to our newsletter below.