Fetching Token Holders
Fetching token holders is a vital process that allows you to obtain a list of all wallets addresses that hold a specific token.
What you'll need:
This is useful for several reasons:
- User Base Identification: You can easily identify your user base by fetching token holders.
- Loyalty Rewards: Reward your loyal users by selectively minting new tokens for them.
- Valuable Insights: Analyze user behavior and interactions to gain valuable insights.
- Engage Power Users: Recognize and engage with influential power users who hold a significant amount of tokens.
- Improved User Experience: By retrieving token holder data, you can enhance the overall user experience and make informed, data-driven decisions.
Fetching Token Holders with the Enjin API
Fetching Tokens Limitations
Please note that the
GetToken
query is limited to tokens from collections that were created via the auth-ed Enjin Platform account.To get a token that was created elsewhere (via a different Enjin Platform account / NFT.io / Enjin Console / etc.) the collection must be "Tracked" first, or the query response will return an error.
Learn more about tracking a collection in the Tracking Collections section below.
To get holders of a specific token, we use the GetToken
query and include the the accounts
in the query response:
Query:
query FetchingTokenHolders{
GetToken(
collectionId: 36105 #Specify the collection ID
tokenId: {integer: 0} #Specify the token ID
){
accounts{
edges{
node{
balance
wallet{
account{
address
}
}
}
}
}
}
}
curl -X POST "https://platform.enjin.io/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: enjin_api_key" \
-d '{"query": "mutation DestroyCollection { DestroyCollection(collectionId: 68844) { id method state } }"}'
using System.Text.Json;
using Enjin.Platform.Sdk;
// Setup the query
var getToken = new GetToken()
.SetCollectionId(36105)
.SetTokenId(new EncodableTokenIdInput().SetInteger(0));
// Define and assign the return data fragment to the query
var tokenFragment = new TokenFragment()
.WithAccounts(new ConnectionFragment<TokenAccountFragment>()
.WithEdges(new EdgeFragment<TokenAccountFragment>()
.WithNode(new TokenAccountFragment()
.WithBalance()
.WithWallet(new WalletFragment()
.WithAccount(new AccountFragment()
.WithAddress()
)
)
)
)
);
getToken.Fragment(tokenFragment);
// Create and auth a client to send the request to the platform
var client = PlatformClient.Builder()
.SetBaseAddress("https://platform.canary.enjin.io")
.Build();
client.Auth("Your_Platform_Token_Here");
// Send the request and write the output to the console.
// Only the fields that were requested in the fragment will be filled in,
// other fields which weren't requested in the fragment will be set to null.
var response = await client.SendGetToken(getToken);
Console.WriteLine(JsonSerializer.Serialize(response.Result.Data));
#include "EnjinPlatformSdk/CoreQueries.hpp"
#include <iostream>
using namespace enjin::platform::sdk;
using namespace std;
int main() {
// Setup an Encodable Token ID
EncodableTokenIdInput tokenId = EncodableTokenIdInput()
.SetInteger(make_shared<SerializableString>("0"));
// Set up the query
GetToken getToken = GetToken()
.SetCollectionId(make_shared<SerializableString>("36105"))
.SetTokenId(make_shared<EncodableTokenIdInput>(tokenId));
// Define and assign the return data fragments to the query
AccountFragment accountFragment = AccountFragment()
.WithAddress();
WalletFragment walletFragment = WalletFragment()
.WithAccount(make_shared<AccountFragment>(accountFragment));
TokenAccountFragment tokenAccountFragment = TokenAccountFragment()
.WithBalance()
.WithWallet(make_shared<WalletFragment>(walletFragment));
EdgeFragment<TokenAccountFragment> edgeFragment = EdgeFragment<TokenAccountFragment>()
.WithNode(make_shared<TokenAccountFragment>(tokenAccountFragment));
ConnectionFragment<TokenAccountFragment> connectionFragment = ConnectionFragment<TokenAccountFragment>()
.WithEdges(make_shared<EdgeFragment<TokenAccountFragment>>(edgeFragment));
TokenFragment tokenFragment = TokenFragment()
.WithAccounts(make_shared<ConnectionFragment<TokenAccountFragment>>(connectionFragment));
getToken.SetFragment(make_shared<TokenFragment>(tokenFragment));
// Create and auth a client to send the request to the platform
unique_ptr<PlatformClient> client = PlatformClient::Builder()
.SetBaseAddress("https://platform.canary.enjin.io")
.Build();
client->Auth("Your_Platform_Token_Here");
// Send the request then get the response and write the output to the console.
// Only the fields that were requested in the fragment will be filled in,
// other fields which weren't requested in the fragment will be set to null.
future<PlatformResponsePtr<GraphQlResponse<Token>>> futureResponse = SendGetToken(*client, getToken);
// Get the platform response holding the HTTP data
PlatformResponsePtr<GraphQlResponse<Token>> response = futureResponse.get();
// Get the result, a GraphQL response, holding the GraphQL data
const optional<GraphQlResponse<Token>>& gqlResult = response->GetResult();
// Write the result data to the console
if (gqlResult.has_value() && gqlResult->IsSuccess())
{
const optional<Token>& getTokenResult = gqlResult->GetData()->GetResult();
std::cout << getTokenResult->GetMinimumBalance().value() << std::endl;
}
// Write any error messages to the console
if (gqlResult.has_value() && gqlResult->HasErrors())
{
const optional<vector<GraphQlError>>& errors = gqlResult->GetErrors();
for (const GraphQlError& error : errors.value()) {
std::cout << error.GetMessage().value() << std::endl;
}
}
client.reset();
return 0;
}
fetch('https://platform.canary.enjin.io/graphql', {
method: 'POST',
headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'},
body: JSON.stringify({
query: `
query FetchingTokenHolders
(
$collection_id: BigInt!
$token_id: BigInt!
) {
GetToken(
collectionId: $collection_id
tokenId: {integer: $token_id}
){
accounts{
edges{
node{
balance
wallet{
account{
address
}
}
}
}
}
}
}
`,
variables: {
collection_id: 36105, //Specify the collection ID
token_id: 0 //Specify the token ID
}
}),
})
.then(response => response.json())
.then(data => console.log(data));
const axios = require('axios');
axios.post('https://platform.canary.enjin.io/graphql', {
query: `
query FetchingTokenHolders
(
$collection_id: BigInt!
$token_id: BigInt!
) {
GetToken(
collectionId: $collection_id
tokenId: {integer: $token_id}
){
accounts{
edges{
node{
balance
wallet{
account{
address
}
}
}
}
}
}
}
`,
variables: {
collection_id: 36105, //Specify the collection ID
token_id: 0 //Specify the token ID
}
}, {
headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
import requests
query = '''
query FetchingTokenHolders
(
$collection_id: BigInt!
$token_id: BigInt!
) {
GetToken(
collectionId: $collection_id
tokenId: {integer: $token_id}
){
accounts{
edges{
node{
balance
wallet{
account{
address
}
}
}
}
}
}
}
'''
variables = {
'collection_id': 36105, #Specify the collection ID
'token_id': 0 #Specify the token ID
}
response = requests.post('https://platform.canary.enjin.io/graphql',
json={'query': query, 'variables': variables},
headers={'Content-Type': 'application/json', 'Authorization': 'Your_Platform_Token_Here'}
)
print(response.json())
Response:
{
"data": {
"GetToken": {
"accounts": {
"edges": [
{
"node": {
"balance": "4",
"wallet": {
"account": {
"address": "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f"
}
}
}
},
{
"node": {
"balance": "2",
"wallet": {
"account": {
"address": "cxJXQKFB4ZWJzutwEtZvTQ9KLucdsaWgzyef5pv9R7x98Dmwp"
}
}
}
}
]
}
}
}
}
Using Pagination
The response may be displayed on several pages. To view all of it, you may need to follow steps for pagination which allows you to flip through the pages.
Fetching Collection Holders with the Enjin API
Fetching Collections Limitations
Please note that the
GetCollections
query is limited to collections that were created via the auth-ed Enjin Platform account.To get a collection that was created elsewhere (via a different Enjin Platform account / NFT.io / Enjin Console / etc.) the collection must be "Tracked" first, or the query response will return an error.
Learn more about tracking a collection in the Tracking Collections section below.
For an NFT collection, we can use the GetCollection
query and include the the accounts
in the query response to find out how many NFTs from the collection are owned by each address.
Query:
query FetchingCollectionHolders{
GetCollection(collectionId: 36105){ #Specify the collection ID
accounts{
edges{
node{
accountCount
wallet{
account{
address
}
}
}
}
}
}
}
curl -X POST "https://platform.enjin.io/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: enjin_api_key" \
-d '{"query": "query FetchingCollectionHolders { GetCollection(collectionId: 36105) { accounts { edges { node { accountCount wallet { account { address } } } } } } }"}'
using System.Text.Json;
using Enjin.Platform.Sdk;
// Setup the query
var getCollection = new GetCollection()
.SetCollectionId(36105);
// Define and assign the return data fragment to the query
var collectionFragment = new CollectionFragment()
.WithAccounts(new ConnectionFragment<CollectionAccountFragment>()
.WithEdges(new EdgeFragment<CollectionAccountFragment>()
.WithNode(new CollectionAccountFragment()
.WithAccountCount()
.WithWallet(new WalletFragment()
.WithAccount(new AccountFragment()
.WithAddress()
)
)
)
)
);
getCollection.Fragment(collectionFragment);
// Create and auth a client to send the request to the platform
var client = PlatformClient.Builder()
.SetBaseAddress("https://platform.canary.enjin.io")
.Build();
client.Auth("Your_Platform_Token_Here");
// Send the request and write the output to the console.
// Only the fields that were requested in the fragment will be filled in,
// other fields which weren't requested in the fragment will be set to null.
var response = await client.SendGetCollection(getCollection);
Console.WriteLine(JsonSerializer.Serialize(response.Result.Data)); CC
#include "EnjinPlatformSdk/CoreQueries.hpp"
#include <iostream>
using namespace enjin::platform::sdk;
using namespace std;
int main() {
// Set up the query
GetCollection getCollection = GetCollection()
.SetCollectionId(make_shared<SerializableString>("36105"));
// Define and assign the return data fragments to the query
CollectionAccountFragment collectionAccountFragment = CollectionAccountFragment()
.WithAccountCount()
.WithWallet(make_shared<WalletFragment>(WalletFragment()
.WithAccount(make_shared<AccountFragment>(AccountFragment()
.WithAddress()
)
)
)
);
EdgeFragment<CollectionAccountFragment> edgeFragment = EdgeFragment<CollectionAccountFragment>()
.WithNode(make_shared<CollectionAccountFragment>(collectionAccountFragment));
ConnectionFragment<CollectionAccountFragment> connectionFragment = ConnectionFragment<CollectionAccountFragment>()
.WithEdges(make_shared<EdgeFragment<CollectionAccountFragment>>(edgeFragment));
CollectionFragment collectionFragment = CollectionFragment()
.WithAccounts(make_shared<ConnectionFragment<CollectionAccountFragment>>(connectionFragment));
getCollection.SetFragment(make_shared<CollectionFragment>(collectionFragment));
// Create and auth a client to send the request to the platform
unique_ptr<PlatformClient> client = PlatformClient::Builder()
.SetBaseAddress("https://platform.canary.enjin.io")
.Build();
client->Auth("Your_Platform_Token_Here");
// Send the request then get the response and write the output to the console.
// Only the fields that were requested in the fragment will be filled in,
// other fields which weren't requested in the fragment will be set to null.
future<PlatformResponsePtr<GraphQlResponse<Collection>>> futureResponse = SendGetCollection(*client, getCollection);
// Get the platform response holding the HTTP data
PlatformResponsePtr<GraphQlResponse<Collection>> response = futureResponse.get();
// Get the result, a GraphQL response, holding the GraphQL data
const optional<GraphQlResponse<Collection>>& gqlResult = response->GetResult();
// Write the result data to the console
if (gqlResult.has_value() && gqlResult->IsSuccess())
{
const optional<Collection>& getCollectionResult = gqlResult->GetData()->GetResult();
std::cout << getCollectionResult->GetCollectionId().value() << std::endl;
}
// Write any error messages to the console
if (gqlResult.has_value() && gqlResult->HasErrors())
{
const optional<vector<GraphQlError>>& errors = gqlResult->GetErrors();
for (const GraphQlError& error : errors.value()) {
std::cout << error.GetMessage().value() << std::endl;
}
}
client.reset();
return 0;
}
fetch('https://platform.canary.enjin.io/graphql', {
method: 'POST',
headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'},
body: JSON.stringify({
query: `
query FetchingCollectionHolders
(
$collection_id: BigInt!
) {
GetCollection(collectionId: $collection_id){
accounts{
edges{
node{
accountCount
wallet{
account{
address
}
}
}
}
}
}
}
`,
variables: {
collection_id: 36105 //Specify the collection ID
}
}),
})
.then(response => response.json())
.then(data => console.log(data));
const axios = require('axios');
axios.post('https://platform.canary.enjin.io/graphql', {
query: `
query FetchingCollectionHolders
(
$collection_id: BigInt!
) {
GetCollection(collectionId: $collection_id){
accounts{
edges{
node{
accountCount
wallet{
account{
address
}
}
}
}
}
}
}
`,
variables: {
collection_id: 36105 //Specify the collection ID
}
}, {
headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
import requests
query = '''
query FetchingCollectionHolders
(
$collection_id: BigInt!
) {
GetCollection(collectionId: $collection_id){
accounts{
edges{
node{
accountCount
wallet{
account{
address
}
}
}
}
}
}
}
'''
variables = {
'collection_id': 36105 #Specify the collection ID
}
response = requests.post('https://platform.canary.enjin.io/graphql',
json={'query': query, 'variables': variables},
headers={'Content-Type': 'application/json', 'Authorization': 'Your_Platform_Token_Here'}
)
print(response.json())
Response:
{
"data": {
"GetCollection": {
"accounts": {
"edges": [
{
"node": {
"accountCount": 3,
"wallet": {
"account": {
"address": "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f"
}
}
}
},
{
"node": {
"accountCount": 2,
"wallet": {
"account": {
"address": "cxJXQKFB4ZWJzutwEtZvTQ9KLucdsaWgzyef5pv9R7x98Dmwp"
}
}
}
}
]
}
}
}
}
Using Pagination
The response may be displayed on several pages. To view all of it, you may need to follow steps for pagination which allows you to flip through the pages.
More Fields and Arguments Available!
The
GetToken
andGetCollection
queries have a range of options beyond the simple examples shown. For full details on these queries, consult the GraphQL Schema on Apollo:
- For
GetToken
query specifics: Apollo GraphQL Schema - GetToken.- For
GetCollection
query specifics: Apollo GraphQL Schema - GetCollection.These links provide the information you need to customize the queries for your needs, including selecting different information about tokens such as attributes and supply details.
Tracking Collections
The GetToken
, GetTokens
, GetCollection
, and GetCollections
queries are limited only to collections and tokens that were created via the auth-ed Enjin Platform account. To use these queries with collections / tokens created externally (via a different Enjin Platform account / NFT.io / Enjin Console / etc.) the collection must be "Tracked" first, or the query response will return an error.
To track a collection, head over to the collections page on Enjin Platform: https://platform.enjin.io/collections, click on the "Track" button, insert the collection ID of the collection you want to track and click "Track".
Need to track collections programmatically?
You can use the
AddToTracked
mutation to track a collection programmatically.
Updated 24 days ago