Tatum
Search…
How to securely store private keys & sign transactions
Set up Tatum KMS to manage your keys

What is KMS?

Tatum Key Management System (KMS) is a comprehensive solution for building custodial apps. In custodial apps, you control your app’s end-users’ private keys and wallet mnemonics. Blockchain transactions are signed locally, and sensitive data is not sent over the Internet.
With KMS, you can easily build and scale custodial apps, provide the highest level of security for your users, and allow them to use blockchain technology without having to deal with private keys and mnemonics. End-users can simply log in to your app with their credentials, and KMS takes care of the rest.

Private keys & mnemonics

Private keys and mnemonics are the only things that can unlock your crypto assets and approve transactions. If you lose access to them, you will lose access to your assets forever. Also, when someone else obtains access to your keys, they can steal all your funds. This is something that you must keep in mind to run your business successfully.
NEVER give access to your mnemonics or private keys to anyone. Your private keys should NEVER leave your secure perimeter and should not be sent over the Internet, not even via HTTPS connection. Tatum will never ask for your keys or mnemonics, and you should NEVER send them to the Tatum API.
There are public endpoints on Tatum API which accept or produce sensitive information like private key or mnemonics. These endpoints are only present for test use and quick prototyping, not for production usage. For production usage, you should leverage Tatum KMS to generate private keys, mnemonics, and sign transactions locally and securely.
Whenever a privateKey or mnemonic field is present in an API endpoint in Tatum, you should replace them with a signatureId generated by KMS.

How does KMS work?

Tatum KMS stores all your mnemonics and private keys in a wallet storage file. This storage file is an AEC encrypted file, for which only you know the encryption key.
Every wallet that is stored inside your KMS has a unique identifier, called signatureId. This signatureId is used in communication with Tatum API and represents the wallet used by the specific operation.
When you generate and store all the wallets you want to work with, you then enable the daemon mode in the KMS. This daemon mode periodically checks for the pending transactions to sign.
Every pending transaction has a signatureId present. When the pending transaction is matched with the wallet storage's specific wallet, it is signed locally and sent to the blockchain. Your wallet data are stored only in memory.
Tatum KMS is shipped as a Node.JS binary, and Node.JS 14+ should be installed on your server. It is a command-line tool and provides two modes of operation:
  • daemon mode is responsible for periodically pulling pending transactions from the Tatum API
  • CLI mode is used to generate wallets or private keys

How to use KMS

In this guide, we’ll learn how to generate wallets, private keys, blockchain addresses, and sign transactions locally using KMS. We’ll be working on the Bitcoin testnet, but the same process applies to any supported blockchain in Tatum.

1. Download and install KMS

  1. 1.
    First, head over to the Tatum GitHub and download KMS.
  2. 2.
    Next, use the following code to install KMS:
Your local server
1
npm i -g @tatumio/tatum-kms
Copied!
For more specifics regarding installation, please consult the Readme included in the GitHub repo.

2. Generate a managed wallet

To generate a wallet that is managed by the KMS, use the generatemanagedwallet command in CLI mode.
Request
1
tatum-kms --path=wallet.dat --testnet generatemanagedwallet BTC
2
3
Enter password to access wallet storage:*****ta
Copied!
The first time you use KMS, you will be prompted to enter a password to encrypt your data. This password is created the first time you enter it, and you should store it in a safe place.
The wallet storage is encrypted with an AEC cipher and is stored on your local server. The password you provide is used to encrypt the mnemonics and private keys inside. If you lose your password, you will lose access to your mnemonics.
The response will look like this, and will contain your wallet mnemonic's signature ID as the first parameter:
Response
1
{
2
"xxx-59be-4792-81c5-yyy": {
3
"mnemonic": "list of long words",
4
"xpub": "tpubBCDEF",
5
"chain": "BTC",
6
"testnet": true
7
}
8
}
Copied!

3. Create a private key

Next, we will generate a private key for our wallet locally. Private keys are used to authorize the transfer of funds from blockchain addresses. Use the getprivatekey command to generate one:
Request
1
tatum-kms --path=wallet.dat --testnet getprivatekey xxx-59be-4792–81c5-yyy 0
Copied!
The parameters required are:
  • Your wallet mnemonic's signature ID —the first parameter in the response to step 2
  • The derivation index of the private key you are generating — this can be any value, but it must be unique to the wallet you are generating. Starting at “0” and working chronologically is a good idea.
The response will be the private key of the derivation index you have specified:
Response
1
{
2
"privateKey": "XXXNAV3tX3vWPG4uThixuqdYYY"
3
}
Copied!

4. Generate an address

Next, we’ll create an address for the private key we have just generated. You can receive funds to the address and use the private key to send them from the address.
Use the getaddress command to generate an address for the same derivation index (0) we specified in step 3:
Request
1
tatum-kms --path=wallet.dat --testnet getaddress xxx-59be-4792–81c5-yyy 0
Copied!
The parameters required are:
  • Your wallet mnemonic's signature ID —the same as above
  • The derivation index of the address you are generating — the same derivation index you specified in step 3.
The response will contain the address you have just generated:
Response
1
{
2
"address": "AAAA3JPvMuwgpKovMTjBBB"
3
}
Copied!

5. Store the private key to your wallet

Now, we will store the private key we have just generated to the wallet. Use the storemanagedprivatekey command to do so:
Request
1
tatum-kms --path=wallet.dat --testnet storemanagedprivatekey BTC
Copied!
You will be prompted to enter the private key you generated above, and the password you created at the beginning:
Enter password + private key
1
Enter private key to store:XXXNAV3tX3vWPG4uThixuqdYYY
2
3
Enter password to access wallet store:******
Copied!
The response will contain the signature ID of the private key, which you can then use to sign transactions.
Response
1
{
2
"signatureId": "QQQ-4b41-4ec9-b66c-WWW"
3
}
Copied!
Now, let’s export our wallet and have a look. Enter the following to export:
Request
1
tatum-kms --path=wallet.dat --testnet export
Copied!
You'll again be prompted to enter your password, and the response will give you details about your wallet:
Response
1
{
2
"QQQ-4b41-4ec9-b66c-WWW": {
3
"privateKey": "XXXNAV3tX3vWPG4uThixuqdYYY",
4
"chain": "BTC",
5
"testnet": true
6
},
7
"xxx-59be-4792-81c5-yyy": {
8
"mnemonic": "list of long words",
9
"xpub": "tpubBCDEF",
10
"chain": "BTC",
11
"testnet": true
12
}
13
}
Copied!

6. Send some test BTC to your new address

Now, use a Bitcoin testnet faucet to send some test BTC to your address. You can use any faucet you’d like, here’s a mobile faucet that works well**.**
Send the test BTC to the Bitcoin address you generated in step 4: AAAA3JPvMuwgpKovMTjBBB

7. Enable daemon mode

Daemon mode is basically background mode. When enabled, Tatum-KMS will work in the background and listen for pending transactions. To enable daemon mode, enter the following code:
Your local server
1
tatum-kms daemon --path=wallet.dat --testnet --chain=BTC --api-key=your-testnet-api-key --period=10
Copied!
You need to enter the password for unlocking the wallet storage. It is required whenever you start the daemon. If your daemon stops, you need to enter the password again when you start it up again.

8. Send an API request to Tatum to perform a transaction

Now you can send bitcoin from your address to any other address. To do so, send a bitcoin transaction API request to Tatum. Instead of a privateKey you should enter a signatureId field that contains your signature ID from step 5:
Request
1
curl --location --request POST 'https://api-eu1.tatum.io/v3/bitcoin/transaction' \
2
--header 'x-api-key: your-tesnet-api-key-from-tatum' \
3
--header 'Content-Type: application/json' \
4
--data-raw '{
5
"fromAddress": [
6
{
7
"address": "AAAA3JPvMuwgpKovMTjBBB", -> FROM STEP 4
8
"signatureId": "QQQ-4b41-4ec9-b66c-WWW" -> FROM STEP 5
9
}
10
],
11
"to": [
12
{
13
"address": "any-existing-testnet-bitcoin-address",
14
"value": 0.00001 -> AMOUNT OF BTC TO SEND
15
}
16
]
17
}'
Copied!
As you can see, there was no private key or mnemonic anywhere in the request, nor was any other sensitive information required.
Be aware that there is a change in the behavior of this operation. The transaction is not yet signed and sent to the blockchain. It is waiting in the Tatum to be processed by the KMS.
When the KMS detects a new pending transaction, it signs it locally and sends it to the blockchain. It must also mark the transaction as processed so that it will not be sent to the blockchain again.‌
When KMS picks up the pending transaction, it will output something like:
Response
1
Processing pending transaction - {
2
"withdrawalId": null,
3
"chain": "BTC",
4
"serializedTransaction": "{\"hash\":\"81e62bdfbfc7bcb66c2a2f17335d033fd98b84c1188a7bb379a2dce9f1cda989\",\"version\":2,\"inputs\":[{\"prevTxId\":\"121702fd7acd1b2cca6bd19658009140730ba26ca67cd222c00f952a111e11f4\",\"outputIndex\":0,\"sequenceNumber\":4294967295,\"script\":\"\",\"scriptString\":\"\",\"output\":{\"satoshis\":2000,\"script\":\"76a914c8e668ee829837a2355c1e234a41f53f86b8156c88ac\"}}],\"outputs\":[{\"satoshis\":1000,\"script\":\"001487c70889f0a1d2f632d216a01472dde71f062aa7\"}],\"nLockTime\":0}",
5
"hashes": [
6
"b8eb99cd-ba04-4031-a65f-11d6420ebdd1"
7
],
8
"index": null,
9
"withdrawalResponses": null,
10
"id": "61fe7c68cf2fbc595cbb89dd"
11
}.
Copied!

9. Get transaction details

Using the KMS transaction ID from the id field of the response to the previous request (“61fe7c68cf2fbc595cbb89dd” in our case above), you can now use the Get transaction details endpoint to get the details of the transaction you have just performed**:**
Request
1
curl --request GET
2
--url https://api-eu1.tatum.io/v3/kms/61fe7c68cf2fbc595cbb89dd
3
--header 'x-api-key: your-testnet-api-key-from-tatum'Example usage of the API with Tatum KMS
Copied!
The response will contain the details of your transaction:
Response
1
{
2
"withdrawalId": null,
3
"chain": "BTC",
4
"serializedTransaction": "{\"hash\":\"81e62bdfbfc7bcb66c2a2f17335d033fd98b84c1188a7bb379a2dce9f1cda989\",\"version\":2,\"inputs\":[{\"prevTxId\":\"121702fd7acd1b2cca6bd19658009140730ba26ca67cd222c00f952a111e11f4\",\"outputIndex\":0,\"sequenceNumber\":4294967295,\"script\":\"\",\"scriptString\":\"\",\"output\":{\"satoshis\":2000,\"script\":\"76a914c8e668ee829837a2355c1e234a41f53f86b8156c88ac\"}}],\"outputs\":[{\"satoshis\":1000,\"script\":\"001487c70889f0a1d2f632d216a01472dde71f062aa7\"}],\"nLockTime\":0}",
5
"hashes": [
6
"b8eb99cd-ba04-4031-a65f-11d6420ebdd1"
7
],
8
"index": null,
9
"withdrawalResponses": null,
10
"txId": "f7572ef070d381612b7594940cc73ec008e796b37a73ff031f3855d2a23c9ade",
11
"id": "61fe7c68cf2fbc595cbb89dd"
Copied!
The response contains a Bitcoin transaction ID in the txId field (“f7572ef070d381612b7594940cc73ec008e796b37a73ff031f3855d2a23c9ade” in our case), which you can use to view the blockchain transaction in any Bitcoin blockchain explorer.

Other KMS features

KMS can be used to securely sign any transaction with a signatureId instead of a privateKey or mnemonic. This includes deploying NFT smart contracts, minting NFTs, transferring ERC-20, ERC-721, and ERC-1155 tokens, and any other transaction that requires a private key or mnemonic to be signed.
Be aware that there are two types of signature IDs generated by KMS: mnemonic signature IDs and private key signature IDs.
  • Any time a private key is required for a request, you need to replace the privateKey field with a signatureId field that contains the signature ID of the private key from the wallet storage.
  • Whenever there is a mnemonic is required to sign a transaction, you need to replace the mnemonic field **** with a signatureId field containing the signature ID of the mnemonic from the wallet storage.
You can also use KMS to get a list of pending transactions to sign, complete pending transactions to sign, and delete transactions waiting to be signed.For a full list of API calls available for Tatum KMS, please refer to our API documentation.
Tatum KMS also supports integrations to Azure Key Vault or VGS so that you can store your keys and mnemonics there. More information can be found on the Tatum KMS GitHub pages, where all of the source code is available.

Great job!

Now you can create super-secure, scalable custodial apps in no time! Stay tuned for more updates and tutorials on different ways to work with Tatum KMS, and check out our Crypto Exchange workshop for more on how to use KMS: