Go SDK for the Tatum API — blockchain infrastructure for developers.
| Platform | URL |
|---|---|
| GitLab (primary) | https://gitlab.com/mayerdev/tatum-sdk-go |
| GitHub (mirror) | https://github.com/mayerdev/tatum-sdk-go |
| Codeberg (mirror) | https://codeberg.org/mayerdev/tatum-sdk-go |
Go module path:
gitlab.com/mayerdev/tatum-sdk-go
go get gitlab.com/mayerdev/tatum-sdk-goimport (
tatum "gitlab.com/mayerdev/tatum-sdk-go"
"gitlab.com/mayerdev/tatum-sdk-go/chain"
)
client, err := tatum.NewClient("your-api-key")
if err != nil {
log.Fatal(err)
}HD wallet generation, address and private key derivation — fully offline, no API calls.
import (
"gitlab.com/mayerdev/tatum-sdk-go/chain"
"gitlab.com/mayerdev/tatum-sdk-go/keygen"
)Generate wallet — returns a 24-word mnemonic and xpub:
w, err := keygen.GenerateWallet(chain.Ethereum)
// w.Mnemonic — "word1 word2 ... word24"
// w.XPub — "xpub6Ev..."Derive address from xpub and index:
addr, err := keygen.DeriveAddress(w.XPub, 0, chain.Ethereum)Derive private key from mnemonic and index (EVM → 0x-prefixed hex, UTXO → WIF):
privKey, err := keygen.DerivePrivateKey(w.Mnemonic, 0, chain.Ethereum)Supported networks:
| Network | Chain | Address format | Key format |
|---|---|---|---|
| Ethereum | chain.Ethereum |
0x... |
0x... hex |
| Polygon | chain.Polygon |
0x... |
0x... hex |
| BNB Smart Chain | chain.BNBSmartChain |
0x... |
0x... hex |
| Avalanche | chain.Avalanche |
0x... |
0x... hex |
| Arbitrum | chain.Arbitrum |
0x... |
0x... hex |
| Optimism | chain.Optimism |
0x... |
0x... hex |
| Base | chain.Base |
0x... |
0x... hex |
| zkSync | chain.ZkSync |
0x... |
0x... hex |
| Linea | chain.Linea |
0x... |
0x... hex |
| Scroll | chain.Scroll |
0x... |
0x... hex |
| Blast | chain.Blast |
0x... |
0x... hex |
| Fantom | chain.Fantom |
0x... |
0x... hex |
| Cronos | chain.Cronos |
0x... |
0x... hex |
| Celo | chain.Celo |
0x... |
0x... hex |
| Gnosis | chain.Gnosis |
0x... |
0x... hex |
| Harmony | chain.Harmony |
0x... |
0x... hex |
| Aurora | chain.Aurora |
0x... |
0x... hex |
| Heco | chain.Heco |
0x... |
0x... hex |
| KuCoin | chain.KuCoin |
0x... |
0x... hex |
| Klaytn | chain.Klaytn |
0x... |
0x... hex |
| Palm | chain.Palm |
0x... |
0x... hex |
| Ethereum Classic | chain.EthereumClassic |
0x... |
0x... hex |
| VeChain | chain.VeChain |
0x... |
0x... hex |
| Hedera | chain.Hedera |
0x... |
0x... hex |
| Chiliz | chain.Chiliz |
0x... |
0x... hex |
| Theta | chain.Theta |
0x... |
0x... hex |
| Tron | chain.Tron |
T... |
0x... hex |
| Bitcoin | chain.Bitcoin |
1... |
WIF |
| Litecoin | chain.Litecoin |
L... |
WIF |
| Dogecoin | chain.Dogecoin |
D... |
WIF |
| Bitcoin Cash | chain.BitcoinCash |
1... |
WIF |
| Dash | chain.Dash |
X... |
WIF |
| ZCash | chain.ZCash |
t1... |
WIF |
| Solana | chain.Solana |
base58 pubkey (see note) | hex |
| XRP | chain.XRP |
r... |
0x... hex |
chains := []chain.Chain{
chain.Ethereum, chain.Polygon, chain.BNBSmartChain, chain.Avalanche,
chain.Arbitrum, chain.Optimism, chain.Base, chain.ZkSync,
chain.Linea, chain.Scroll, chain.Blast, chain.Fantom,
chain.Cronos, chain.Celo, chain.Gnosis, chain.Harmony,
chain.Aurora, chain.Heco, chain.KuCoin, chain.Klaytn,
chain.Palm, chain.EthereumClassic, chain.VeChain, chain.Hedera,
chain.Chiliz, chain.Theta, chain.Tron,
chain.Bitcoin, chain.Litecoin, chain.Dogecoin, chain.BitcoinCash,
chain.Dash, chain.ZCash,
chain.Solana, chain.XRP,
}
for _, c := range chains {
w, err := keygen.GenerateWallet(c)
if err != nil {
log.Fatal(err)
}
addr, err := keygen.DeriveAddress(w.XPub, 0, c)
if err != nil {
log.Fatal(err)
}
privKey, err := keygen.DerivePrivateKey(w.Mnemonic, 0, c)
if err != nil {
log.Fatal(err)
}
fmt.Printf("chain=%s\n mnemonic=%s\n xpub=%s\n address=%s\n privkey=%s\n\n",
c, w.Mnemonic, w.XPub, addr, privKey)
}Solana multi-address derivation: Because SLIP-0010 with ed25519 only supports hardened child derivation, public-key child derivation is cryptographically impossible for Solana. As a result,
DeriveAddress(xpub, index, chain.Solana)only works forindex == 0(it returns the xpub itself). Forindex > 0it returnskeygen.ErrSolanaPublicDerivation. To derive multiple Solana addresses, useDerivePrivateKeywith the desired index and then convert withSolanaAddressFromPrivKey:privKey, err := keygen.DerivePrivateKey(w.Mnemonic, 5, chain.Solana) addr, err := keygen.SolanaAddressFromPrivKey(privKey)
Unsupported networks return keygen.ErrUnsupportedChain:
_, err := keygen.GenerateWallet(chain.Cardano)
if errors.Is(err, keygen.ErrUnsupportedChain) {
// handle unsupported chain
}Generate wallets and derive addresses/keys via Tatum's REST API (server-side, 17 chains).
Generate wallet:
w, err := client.WalletGen.GenerateWallet(ctx, chain.Ethereum)
// w.Mnemonic — "word1 word2 ... word24"
// w.XPub — "xpub6Ev..."
// For Solana: w.Address, w.PrivateKey
// For Algorand: w.Address, w.SecretDerive address from xpub and index:
addr, err := client.WalletGen.DeriveAddress(ctx, chain.Bitcoin, xpub, 0)Derive private key from mnemonic and index:
key, err := client.WalletGen.DerivePrivateKey(ctx, chain.Ethereum, mnemonic, 0)
if errors.Is(err, walletgen.ErrNotSupported) {
// chain does not support this operation
}Supported chains and operations:
| Chain | GenerateWallet |
DeriveAddress |
DerivePrivateKey |
|---|---|---|---|
chain.Bitcoin |
✓ | ✓ | ✓ |
chain.BitcoinCash |
✓ | ✓ | ✓ |
chain.Dogecoin |
✓ | ✓ | ✓ |
chain.Litecoin |
✓ | ✓ | ✓ |
chain.Ethereum |
✓ | ✓ | ✓ |
chain.BNBSmartChain |
✓ | ✓ | ✓ |
chain.Polygon |
✓ | ✓ | ✓ |
chain.Klaytn |
✓ | ✓ | ✓ |
chain.KuCoin |
✓ | ✓ | ✓ |
chain.VeChain |
✓ | ✓ | ✓ |
chain.Harmony |
✓ | ✓ | ✓ |
chain.Tron |
✓ | ✓ | ✓ |
chain.XDC |
✓ | ✓ | ✓ |
chain.Solana |
✓ | — | — |
chain.Algorand |
✓ | — | — |
chain.Flow |
✓ | ✓ | ✓ |
chain.EGLD |
✓ | — | ✓ |
Flow address derivation: Flow uses a different API path for address derivation (
/v3/flow/pubkey/{xpub}/{index}instead of the standard/v3/{chain}/address/{xpub}/{index}).DeriveAddresshandles this automatically. The wallet response for Flow containsw.Address(the public key / address).DerivePrivateKeyreturns theprivateKeyfield from the API response.
items, err := client.Wallet.GetPortfolio(ctx, wallet.PortfolioRequest{
Addresses: []string{"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},
Chain: "ethereum",
})
balance, err := client.Wallet.GetBalanceByTime(ctx, wallet.BalanceByTimeRequest{
Address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
Chain: "ethereum",
Time: 1700000000,
})
utxos, err := client.Wallet.GetUTXOs(ctx, wallet.UTXORequest{
Address: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
Chain: "bitcoin",
})txs, err := client.Transactions.GetHistory(ctx, transactions.HistoryRequest{
Address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
Chain: "ethereum",
PageSize: 10,
})
tx, err := client.Transactions.GetByHash(ctx, transactions.ByHashRequest{
Hash: "0xabc123...",
Chain: "ethereum",
})block, err := client.Blockchain.GetCurrentBlock(ctx, blockchain.CurrentBlockRequest{
Chain: "ethereum",
})
balance, err := client.Blockchain.GetNativeBalance(ctx, blockchain.NativeBalanceRequest{
Address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
Chain: "ethereum",
})meta, err := client.NFT.GetMetadata(ctx, nft.MetadataRequest{
TokenID: "1",
Contract: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
Chain: "ethereum",
})
tokens, err := client.NFT.GetCollectionTokens(ctx, nft.CollectionTokensRequest{
Collection: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
Chain: "ethereum",
PageSize: 20,
})transfers, err := client.Token.GetTransfers(ctx, token.TransfersRequest{
Address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
Chain: "ethereum",
})
rate, err := client.Token.GetExchangeRates(ctx, token.ExchangeRatesRequest{
Contract: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
Chain: "ethereum",
})rate, err := client.Prices.GetRate(ctx, prices.RateRequest{
Currency: "BTC",
BasePair: "USD",
})
candles, err := client.Prices.GetOHLCV(ctx, prices.OHLCVRequest{
Currency: "ETH",
BasePair: "USD",
From: 1700000000,
To: 1700086400,
})assets, err := client.Staking.GetStakedAssets(ctx, staking.StakedAssetsRequest{
Address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
Chain: "ethereum",
})
validators, err := client.Staking.GetValidators(ctx, staking.ValidatorsRequest{
Chain: "ethereum",
})events, err := client.DeFi.GetEvents(ctx, defi.EventsRequest{
Contract: "0xUniswapV3Pool...",
Chain: "ethereum",
})
latest, err := client.DeFi.GetLatestBlock(ctx, defi.LatestBlockRequest{
Chain: "ethereum",
})gas, err := client.Fees.EstimateGas(ctx, fees.EstimateGasRequest{
Chain: "ethereum",
From: "0xSender",
To: "0xReceiver",
Value: "1000000000000000000",
})
fee, err := client.Fees.GetBlockchainFee(ctx, fees.BlockchainFeeRequest{
Chain: "ethereum",
})resolved, err := client.NameService.Resolve(ctx, nameservice.ResolveRequest{
Name: "vitalik.eth",
Chain: "ethereum",
})check, err := client.Security.CheckAddress(ctx, security.CheckAddressRequest{
Address: "0xSomeAddress",
Chain: "ethereum",
})
if check.Malicious {
log.Println("address flagged as malicious:", check.Tags)
}Subscribe / unsubscribe:
sub, err := client.Notifications.Create(ctx, notifications.CreateRequest{
Type: "ADDRESS_TRANSACTION",
Address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
Chain: "ethereum",
URL: "https://your-webhook.example.com/hook",
})
list, err := client.Notifications.List(ctx, notifications.ListRequest{PageSize: 10})
err = client.Notifications.Cancel(ctx, notifications.CancelRequest{ID: sub.ID})HMAC webhook authentication:
Enable HMAC signing so every webhook from Tatum contains an x-payload-hash header:
err = client.Notifications.EnableHMAC(ctx, notifications.EnableHMACRequest{
HMACSecret: "c354b83b-d31b-4dda-9bab-d6a67715a1ed",
})
err = client.Notifications.DisableHMAC(ctx)Parsing and verifying incoming webhooks:
import "gitlab.com/mayerdev/tatum-sdk-go/notifications"
// In your HTTP handler:
body, _ := io.ReadAll(r.Body)
xPayloadHash := r.Header.Get("x-payload-hash")
payload, valid, err := notifications.ParseAndVerifyWebhook(body, xPayloadHash, "your-hmac-secret")
if err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
if !valid {
http.Error(w, "invalid signature", http.StatusUnauthorized)
return
}
fmt.Println(payload.Chain, payload.Address, payload.Amount, payload.TxID)Pass an empty string as hmacSecret to skip signature verification and only parse the payload.
WebhookPayload fields:
| Field | Type | Description |
|---|---|---|
Address |
string |
Subscribed address |
Amount |
string |
Transfer amount |
CounterAddress |
string |
Counterpart address |
Asset |
string |
Asset symbol |
BlockNumber |
int64 |
Block number |
TxID |
string |
Transaction hash |
Type |
string |
"native" or "token" |
TokenID |
*string |
Token ID (nullable) |
ContractAddress |
string |
Token contract address |
Chain |
string |
Blockchain identifier |
SubscriptionType |
string |
e.g. "ADDRESS_EVENT" |
result, err := client.RPC.Call(ctx, chain.Ethereum, chain.Mainnet, "eth_blockNumber", nil)
result, err := client.RPC.Call(ctx, chain.Ethereum, chain.Mainnet, "eth_getBalance", []any{
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"latest",
})Supported chains:
chain.Ethereum, chain.Bitcoin, chain.Polygon, chain.BNBSmartChain,
chain.Solana, chain.Avalanche, chain.Tron, chain.Optimism,
chain.Arbitrum, chain.Base, chain.ZkSync, chain.Linea,
// ... and 35+ more_, err := client.Wallet.GetPortfolio(ctx, req)
if err != nil {
if tatum.IsNotFound(err) {
// 404
}
if tatum.IsRateLimit(err) {
// 429 — SDK automatically retries with exponential backoff
}
var apiErr *tatum.APIError
if errors.As(err, &apiErr) {
fmt.Println(apiErr.StatusCode, apiErr.ErrorCode, apiErr.Message)
}
}The client automatically retries on 429, 502, 503, 504 responses using exponential backoff.
txs, err := client.Transactions.GetHistory(ctx, transactions.HistoryRequest{
Address: "0x...",
Chain: "ethereum",
PageSize: 50,
Cursor: "",
})Pass the cursor from the previous response to fetch the next page.
client, err := tatum.NewClient("your-api-key",
tatum.WithBaseURL("https://api.tatum.io"),
tatum.WithTimeout(15*time.Second),
tatum.WithRetries(5),
tatum.WithUserAgent("my-app/1.0"),
tatum.WithRPCBaseURL("https://%s-%s.gateway.tatum.io/"),
)- Go 1.25+
- Tatum API key: https://tatum.io
MIT