# How to migrate from BCD to TzKT API
With the recent major update of TzKT API we can finally offer a fully-fledged alternative to BCD users. It is performant, stable, feature-rich, and covers much more use cases than ever.
# Main differences
# Multinetwork API 🠒 subdomain per network
In BCD network
is part of the query string while on TzKT you have to use different subdomains api.{network}.tzkt.io
(api.tzkt.io
is actually an alias for api.mainnet.tzkt.io
).
# Page size: 10 🠒 10000
In BCD we were forced to dramatically reduce the page size in order to handle the load, in TzKT you can do far fewer requests. But don't relax too much, you'll still need pagination 😃
# Metadata: snake case 🠒 camel case
In BCD we do parse and validate TZIP-12|TZIP-21 fields and return them in a structured manner. Unfortunately, since our entire API layout has snake case it ended up with metadata fields differ from their original key names, e.g. thumbnailUri (original)
🠒 thumbnail_uri (bcd)
. We realized it too late, when changing it would break many API clients.
In TzKT token (and contract) metadata is returned as is, without any modifications, thus you will deal with camel case (as per TZIP-12|TZIP-21 standards).
# Storage & parameters: Miguel 🠒 humanified JSON
The format BCD uses to encode contract storage and operation parameters is basically a transformed Micheline extended with certain extra information required to render the rich user interface. We call it Miguel and it's very far from being a human-readable target and even machine-readable format, it's designed for a very specific purpose.
On the contrary, TzKT APi provides a "humanified" JSON representation of the Michelson structures, no matter how complex and nested they are. Easy to read, easy to parse.
# Top 10 BCD endpoints
Here is a short migration guide for top 10 popular API endpoints.
# /v1/account/{network}/{address}/token_balances
Returns a list of tokens (balance + metadata) a particular account owns.
The accorging TzKT replacement for this call is /v1/tokens/balances.
# Pagination
BCD has a strict limitation on how many items you can request at once, TzKT is much more democratic in that sense, but still you have to iterate over the balances in case an account owns several thousands of tokens.
- https://api.better-call.dev/v1/account/mainnet/tz1QcqnzZ8pa6VuE4MSeMjsJkiW94wNrPbgX/token_balances?offset=610&size=1
+ https://api.tzkt.io/v1/tokens/balances?account=tz1QcqnzZ8pa6VuE4MSeMjsJkiW94wNrPbgX&limit=1&offset=250
You might also noticed that BCD also adds the total number of tokens to the response, here's how you can get that summary with TzKT:
https://api.tzkt.io/v1/tokens/balances/count?account=tz1QcqnzZ8pa6VuE4MSeMjsJkiW94wNrPbgX
# Filter by contract
If you are building a multi-level token navigation you might want to group balances by dapp and allow users to "drill down" to see tokens for that particular contract(s). Filtering by token contract address is what you need in that case.
- https://api.better-call.dev/v1/account/mainnet/tz1Uza3jMhipiQMtmeEidizjbSqnqZMQyRv7/token_balances?contract=KT1K4jn23GonEmZot3pMGth7unnzZ6EaMVjY&1644384642198
+ https://api.tzkt.io/v1/tokens/balances?account=tz1Uza3jMhipiQMtmeEidizjbSqnqZMQyRv7&token.contract=KT1K4jn23GonEmZot3pMGth7unnzZ6EaMVjY
# Filter by balance
Hiding null balances is an essential thing if you are handling numerous tokens, it allows to show the user only the relevant information.
- /v1/account/mainnet/tz1WHUWCMqVqq5AagGN5DrytqWz88tYgedUr/token_balances?size=50&hide_empty=true
+ https://api.tzkt.io/v1/tokens/balances?account=tz1WHUWCMqVqq5AagGN5DrytqWz88tYgedUr&limit=50&balance.gt=0
# More use cases
Read our recent article to get more insights on what you can do with the new TzKT API.
NOTE
When working with token metadata it's highly recommended to use deep selectors to reduce the network traffic, e.g.:
https://api.tzkt.io/v1/tokens/transfers?token.id=778919&sort.desc=id&limit=2&select=from.address%20as%20src,to.address%20as%20dst,amount,token.metadata.symbol%20as%20symbol,token.metadata.decimals%20as%20decimals
will result in
{
"src": "tz1eVjytct5fWpp646fKTK2ULYtVPVYpFmQF",
"dst": "KT1HbQepzV1nVGg8QVznG7z4RcHseD5kwqBn",
"amount": "5",
"symbol": "OBJKT",
"decimals": 0
}
which is much clear and lightweight than joining the entire TZIP-12 JSON.
# /v1/tokens/{network}/transfers/{address}
Returns a list of token transfers (FA1.2|FA2) where either source or destination equal to the given address.
The according TzKT endpoint is /v1/tokens/transfers.
# Pagination
BCD uses cursor pagination for this call, same can be achieved in TzKT. You should use id
as cursor field, because it's non-duplicate and monotonically increasing.
- https://api.better-call.dev/v1/tokens/mainnet/transfers/tz1gvS6JzZFiVrQxJik8ZaHDHk6LRecncSVH?last_id=18823816
+ https://api.tzkt.io/v1/tokens/transfers?anyof.from.to=tz1gvS6JzZFiVrQxJik8ZaHDHk6LRecncSVH&offset.cr=134802352
# Sorting
Depending on your task you might want to get only latest transfers (e.g. wallet workflow) or iterate from oldest to newest.
- https://api.better-call.dev/v1/tokens/mainnet/transfers/tz1gvS6JzZFiVrQxJik8ZaHDHk6LRecncSVH?sort=desc
+ https://api.tzkt.io/v1/tokens/transfers?anyof.from.to=tz1gvS6JzZFiVrQxJik8ZaHDHk6LRecncSVH&sort.desc=timestamp
# /v1/account/{network}/{address}/count
This is a wallet-specific endpoint allowing to get total number of tokens owned aggregated by token contract. This is quite heavy aggregation that does not perform good on accounts that owns thousands of tokens. In TzKT there are no direct replacements, but due to higher limits (page size = 10k) you can ususally achieve the same result with just few extra calls.
- https://api.better-call.dev/v1/account/mainnet/tz1NVUor94eFRvL5ijsJi5BD4qCoHEnrm7qn/count
+ https://api.tzkt.io/v1/tokens/balances?account=tz1NVUor94eFRvL5ijsJi5BD4qCoHEnrm7qn&select=token.contract.address
# /v1/account/{network}/{address}
Returns general information about a particular account (works both for implicit acccounts and originated contracts).
The according TzKT call is /v1/accounts/{address}.
- https://api.better-call.dev/v1/account/mainnet/tz2CduhCSfXqQUPf2zC7qDKtqhXLdBwmzuDq
+ https://api.tzkt.io/v1/accounts/tz2CduhCSfXqQUPf2zC7qDKtqhXLdBwmzuDq
# /v1/contract
Returns basic info about a particular smart contract.
The respectful replacement is /v1/contracts/{address}.
- https://api.better-call.dev/v1/contract/mainnet/KT1VEhYnyUpxtJPAdpAW8NZhhSzCAYFCf1oE
+ https://api.tzkt.io/v1/contracts/KT1VEhYnyUpxtJPAdpAW8NZhhSzCAYFCf1oE
# /v1/contract/tokens
Lists all the tokens minted in this conract.
The accorging TzKT endpoint is /v1/tokens.
# Pagination
In BCD it's size/offset pagination, in TzKT there are similar limit/offset fields, or you use a cursor over id
(internal ID) or tokenId
(only for the single contract scope).
- https://api.better-call.dev/v1/contract/mainnet/KT1ViVwoVfGSCsDaxjwoovejm1aYSGz7s2TZ/tokens?size=10&offset=10
+ https://api.tzkt.io/v1/tokens?contract=KT1ViVwoVfGSCsDaxjwoovejm1aYSGz7s2TZ&offset=10&limit=10
# Filter by token
Sometimes you need to retrieve a particular token metadata.
- https://api.better-call.dev/v1/contract/mainnet/KT1ViVwoVfGSCsDaxjwoovejm1aYSGz7s2TZ/tokens?token_id=31995
+ https://api.tzkt.io/v1/tokens?contract=KT1ViVwoVfGSCsDaxjwoovejm1aYSGz7s2TZ&tokenId=31995
# /v1/contract/{network}/storage
Most dapp data is typically stored in big maps, however sometimes you just need to check the storage itself, for instance if you are querying AMM pool sizes in order to determine md price.
The according TzKT endpoint is /v1/contracts/{address}/storage
- https://api.better-call.dev/v1/contract/mainnet/KT1VEhYnyUpxtJPAdpAW8NZhhSzCAYFCf1oE/storage
+ https://api.tzkt.io/v1/contracts/KT1VEhYnyUpxtJPAdpAW8NZhhSzCAYFCf1oE/storage
# /v1/contract/{network}/{address}/tokens/holders?token_id={token_id}
Returns current holders of a particular token and their balances (which are greater than zero obviously).
The TzKT replacement is again /v1/tokens/balances but with some filters.
- https://api.better-call.dev/v1/contract/mainnet/KT1RJ6PbjHpwc3M5rw5s2Nbmefwbuwbdxton/tokens/holders?token_id=625848
+ https://api.tzkt.io/v1/tokens/balances?token.contract=KT1RJ6PbjHpwc3M5rw5s2Nbmefwbuwbdxton&token.tokenId=625848&balance.gt=0&select.values=account.address,balance
Note that you still have to paginate in case there are more than 10k holders.
# /v1/tokens/{network}/metadata
Lists all the tokens with their metadata.
The according TzKT call is /v1/tokens
- https://api.better-call.dev/v1/tokens/mainnet/metadata
+ https://api.tzkt.io/v1/tokens
# Filter by contact and token_id
This is pretty much the same you can achieve with contract/tokens
endpoint, but nevertheless.
- https://api.better-call.dev/v1/tokens/mainnet/metadata?contract=KT1RJ6PbjHpwc3M5rw5s2Nbmefwbuwbdxton&token_id=508769
+ https://api.tzkt.io/v1/tokens?contract=KT1RJ6PbjHpwc3M5rw5s2Nbmefwbuwbdxton&tokenId=508769
# /v1/bigmap/{network}/{big_map_id}/keys
Returns all keys and current values for a particular big map.
The respectfull TzKT endpoint is /v1/bigmaps/{big_map_id}/keys
- https://api.better-call.dev/v1/bigmap/mainnet/11934/keys
+ https://api.tzkt.io/v1/bigmaps/11934/keys
# Filter by key
Typically you want to get the value for a particular key, in BCD it's done via searching by key and value strings (meaning that it will return all the entries where either key or value contains the string). In TzKT you can specify the path to the key|value subfield to filter by.
- https://api.better-call.dev/v1/bigmap/mainnet/11934/keys?q=tz1PSiE9EmFbQFb7K1cBxPTsbPdgotHLdy9e
+ https://api.tzkt.io/v1/bigmaps/11934/keys?key=tz1PSiE9EmFbQFb7K1cBxPTsbPdgotHLdy9e
A more sophisticated example:
https://api.tzkt.io/v1/bigmaps/511/keys?key.address=tz1UBZUkXpKGhYsP5KtzDNqLLchwF4uHrGjw&key.nat=152
# Why we have two similar APIs
Better Call Dev is historically a developer tool focused on the UI and the very first version was serverless in the sense that it could work using just your RPC node. That was in the early days of Tezos when the entire blockchain was just few gigabytes in size. With the emerging dapp development we realized the need in our own backend to ensure the same good UX but for much larger data volumes. What we have in BCD is sometimes called BFF (backend for front), it's an API tailored to the needs of a specific application, in our case — the better-call.dev site.
At that time, our independence from third-party customers allowed us to introduce new features and break backward compatibility very quickly. When we got our first big external traffic — it was after HEN began to gain popularity — we realized that we were completely unprepared for this turn of events, and to stay functional we focused on scaling and maintaining the infrastructure.
Unlike BCD, our other product TzKT was API-first from the very beginning. It means much more flexible and generic queries, stable API layout with proper deprecation workflow, etc. In TzKT we took into account all the mistakes and insights gained during the development of BCD, which was a pioneer in its own way in many things. It absolutely does not mean that we stop support and work on Better Call Dev API, it means that now you can upgrade to a better alternative with minimal changes and get new features.
# What is the roadmap for BCD API
Better Call Dev API will remain public until the Ithaca upgrade, after that it will still be operational and will continue to power the BCD site, but the response layout can be changed and become backward incompatible.
If you have any questions or issues while migrating please join our Discord server and ask for assistance in #bcd-support channel.
Thank you for using our services 😃