B9lab Logo
Tezos Developer Portal
Developer PortalDeveloper Portal

TzKT API

Fetching information from the Tezos blockchain


Reading Time: 316 min

TzKT is a Tezos blockchain indexer.

We have talked about how a blockchain includes a lot of transactions and information. Working directly on the whole blockchain to fetch and process data will be time consuming. The TzKT indexer can reduce this time and in addition, offers high-level functionalities, which are not provided by the Tezos JSON/RPC interface.

You can install or build it, and configure it for the testnet.

At this point, we want to learn how to work with the TzKT API. Therefore, we will work with a public endpoint.

info icon

You want an overview of the provided TzKT APIs and staging environments for testing, take a look here.

For the mainnet, we have:

https://api.tzkt.io/

and for Florencenet, we can use:

https://api.florencenet.tzkt.io/

Fetching data with Node.js

Because TzKT offers a REST API, we could work with any language or tool which supports HTTP requests. Here we want to work with Node.js and request.

Create a folder and an index.js in it:


const request = require('request');

request('https://api.florencenet.tzkt.io/v1/accounts?limit=10&select=balance&sort.desc=balance', (err, res, body) => {
  console.log(body);
});

Now run:

$ npm install request

and

$ node index.js

We limit the output to 10 accounts, and we want to fetch the account balance for those 10.

It is important that you first think about what you want to get before making a request, because it will impact the performance.

You can specify select, and use select.fields or select.values to fetch the fields or the values. As you can see in the request, we can also tell TzKT API to sort the balances. This will give us the 10 richest accounts.

tip icon

Using data filters on the Tezos API, instead of on the client, helps increase performance and reduce the risk of errors by developing on the TzKT API. Thus, applying them can be understood as a best practice for developers.

Additionally, we can apply some filters through the API:

const request = require('request');

request('https://api.florencenet.tzkt.ioo/v1/accounts?balance.gt=10000000000000', (err, res, body) => {
  console.log(body);
});

This finds you an account with a balance greater than 10 million tez.

warn icon

The amount of endpoints TzKT offers is huge. Each is documented, and you can find in the QUERY PARAMETERS filters to apply and in the RESPONSE SCHEMA the fields you can fetch. Please take your time and have a look into the documentation, e.g. look for different query modes:

queryparams

Let's fetch the storage of our certification smart contract:

const request = require('request');

request('https://api.florencenet.tzkt.io/v1/contracts/KT1SgX1ZehTysGcNoSwypwg6Xs5Cj7cpokwK/storage', 
  (err, res, body) => {
  console.log(JSON.parse(body));
});

You see that the response is a JSON, which we can parse:

{
   "certified":[
      "tz1YTVs4uDn1jEQ2Z4RJyR47zAzhXv1b9Q7t",
      "KT1SgX1ZehTysGcNoSwypwg6Xs5Cj7cpokwK",
      "tz1ZRdP17rsZ1DqUbrraQhbcacVHyh4E6Dkw",
      "tz1Q2zkgZENNF2g95NN7g1CtxAqKynWViSeN"
   ],
   "certifier":"tz1WNmpLG56yT4XixkCFe5M5NpZ7gPgVpVqc"
}

TzKT offers deep selection, so we don't need to fetch the whole storage if we are interested in knowing the certifier:

https://api.florencenet.tzkt.io/v1/contracts/KT1SgX1ZehTysGcNoSwypwg6Xs5Cj7cpokwK/storage?path=certifier

We do not have such a complex data structure but you could access deeper fields with path=certifier.field, etc. - if there were any.

Now the question arises: If we want to track the activity on our smart contract, how often do we need to conduct this request?

tip icon

It is a recommended best practice when using the TzKT API to not conduct the same data request until there has been a change. Being aware of how often data updates occur, helps you define how often you want to request data.

You know that each transaction needs to be included into a block. So we don't need to fetch data more often than blocks appear. We can fetch the protocol constants and use the timeBetweenBlocks value to estimate the arrival time for the next block. Notice, usually you would also wait more than one block to confirm a transaction.

With request-promise:

$ npm install request

we can do:


const request = require('request-promise');

const timeBetweenBlocks = () => {
  return request("https://api.florencenet.tzkt.ioo/v1/protocols/current")
    .then(body => JSON.parse(body).constants.timeBetweenBlocks);
}

const blockTime = () => {
  return request('https://api.florencenet.tzkt.io/v1/head')
    .then(body => Date.parse(JSON.parse(body).timestamp));
}

const contractStorage = (address) => {
  return request('https://api.florencenet.tzkt.io/v1/contracts/' + address + '/storage')
    .then(body => JSON.parse(body));
}

const sleep = (milliseconds) => new Promise(resolve => setTimeout(resolve, milliseconds));

async function main() {
  const timeBlocks = await timeBetweenBlocks(),
    timeRequest = 5000;

  let nextBlockTime = await blockTime() + timeBlocks;

  while(true) {
    if(Date.now() >= nextBlockTime) {
      nextBlockTime = await blockTime() + timeBlocks;
      console.log(await contractStorage("KT1SgX1ZehTysGcNoSwypwg6Xs5Cj7cpokwK"));
    }

    await sleep(timeRequest);
  }
}

main();

This will wait timeBetweenBlocks from the timestamp of the last recent block before fetching the timestamp of the most recent block. Also, even after the time passed, it won't do more than one request each 5 seconds. This should be enough to have an accurate storage.

Notice, we didn't catch any error above, but you should always check for the response if you work with an API.

tip icon

You can also try the WebSocket API JS simple client and subscribe to events. This will reduce the traffic further and make the data real-time available.

We can also look for specific entry point calls or parameters in the transactions. Let's confirm with filtering that tz1YTVs4uDn1jEQ2Z4RJyR47zAzhXv1b9Q7t is certified by tz1WNmpLG56yT4XixkCFe5M5NpZ7gPgVpVqc:

https://api.florencenet.tzkt.io/v1/operations/transactions?target=KT1SgX1ZehTysGcNoSwypwg6Xs5Cj7cpokwK&parameter=tz1YTVs4uDn1jEQ2Z4RJyR47zAzhXv1b9Q7t&select=sender

which will give you:

[{"address":"tz1WNmpLG56yT4XixkCFe5M5NpZ7gPgVpVqc"}]

Let's do something else not easy to do without the TzKT API and ask for the number of smart contracts in Florencenet:

https://api.florencenet.tzkt.io/v1/accounts/count?type=contract

Another important request you will want to do is to fetch the supported protocols:

https://api.florencenet.tzkt.io/v1/protocols

this will give you:

[
   {
      "code":-1,
      "hash":"PrihK96nBAFSxVL1GLJTVhu9YnzkMFiBeuJRPA8NwuZVZCE1L6i",
      "firstLevel":0,
      "lastLevel":0,
      "constants":{
        ...
      }
   },
   {
      "code":0,
      "hash":"PtYuensgYBb3G3x1hLLbCmcav8ue8Kyd2khADcL5LsT5R1hcXex",
      "firstLevel":1,
      "lastLevel":1,
      "constants":{
        ...
      }
   },
   {
      "code":1,
      "hash":"PsFLorenaUUuikDWvMDr6fGBRG8kt3e3D3fHoXK1j1BFRxeSH4i",
      "firstLevel":2,
      "constants":{
        ...
      }
   }
]

There you see the protocol constrains in the constants and the regarding protocol hash:

  • PrihK96nBAFSxVL1GLJTVhu9YnzkMFiBeuJRPA8NwuZVZCE1L6i: Genesis block;
  • PtYuensgYBb3G3x1hLLbCmcav8ue8Kyd2khADcL5LsT5R1hcXex: Genesis protocol;
  • PsFLorenaUUuikDWvMDr6fGBRG8kt3e3D3fHoXK1j1BFRxeSH4i: Florencenet protocol.

So the current protocol is PsFLorenaUUuikDWvMDr6fGBRG8kt3e3D3fHoXK1j1BFRxeSH4i.

tip icon

You can see supported Tezos protocols on tzkt.io and check the details, e.g. for the Florence protocol details.

reading icon
Discuss on Slack
Rate this Page
Would you like to add a message?
Submit
Thank you for your Feedback!