Custodial managed wallets

Custodial API is a set of operatinos, which allows you to work with managed blockchain addresses without having its private key. You can easily create new managed address and export its details - with private key as well - once required.
This features are currently in Alpha version.

Create managed address

2 credits per API call, 10 credits for each managed wallet every day.


Create new managed address for a specific chain. If the address is mainnet or testnet one depends on the API Key - testnet API Key manages testnet addresses, mainnet API Key manages mainnet addresses. Result of the operation is address and walletId, which is used for identifying the wallet later on and/or exporting the private key if needed.
Free users can manage only 10 addresses per API Key.

SecurityX-API-Key
Request
Request Body schema: application/json
chain
required
string
Enum: "BSC" "ETH" "KLAY" "ONE" "CELO" "MATIC" "SOL" "LTC" "BTC"
Responses
200

OK

400

Bad Request. Validation failed for the given object in the HTTP Body or Request parameters.

401

Unauthorized. Not valid or inactive subscription key present in the HTTP Header.

500

Internal server error. There was an error on the server during the processing of the request.

post/v3/custodial/wallet
Request samples
application/json
{
  • "chain": "SOL"
}
Response samples
application/json
{
  • "address": "8oJ8KRL87ja7DjPSsmBG1KtfrpsfLGDMJDGzev68DGqx",
  • "walletId": "52901013-94ab-4124-8645-acba4ee90bb8",
  • "chain": "SOL",
  • "privateKey": "4jCFiqh3tLxKxt3vYW478qodivkCkSzqtpG4wqEaYkgdVC1o79a1VJTc5UiCmCmZBwoJmjaenfYH1ML7ra8vbNpA"
}

Get managed addresses

1 credit per API call.


Get all managed addresses for an API Key.

SecurityX-API-Key
Responses
200

OK

400

Bad Request. Validation failed for the given object in the HTTP Body or Request parameters.

401

Unauthorized. Not valid or inactive subscription key present in the HTTP Header.

500

Internal server error. There was an error on the server during the processing of the request.

get/v3/custodial/wallet
Request samples
curl -i -X GET \
  https://api-eu1.tatum.io/v3/custodial/wallet \
  -H 'x-api-key: YOUR_API_KEY_HERE'
Response samples
application/json
[
  • {
    }
]

Get managed address

1 credit per API call.


Get managed address for an API Key. It's possible to export the private key, if query parameter export is set to true.

SecurityX-API-Key
Request
path Parameters
id
required
string <uuid>

WalletID of the managed address

Example: 3ad54647-4166-4d34-9186-fd46caaba945
query Parameters
export
boolean
Default: false

If set to, export the private key details in the response

Enum: true false
Responses
200

OK

400

Bad Request. Validation failed for the given object in the HTTP Body or Request parameters.

401

Unauthorized. Not valid or inactive subscription key present in the HTTP Header.

500

Internal server error. There was an error on the server during the processing of the request.

get/v3/custodial/wallet/{id}
Request samples
curl -i -X GET \
  'https://api-eu1.tatum.io/v3/custodial/wallet/{id}?export=true' \
  -H 'x-api-key: YOUR_API_KEY_HERE'
Response samples
application/json
[
  • {
    }
]

Delete managed address

1 credit per API call.


Delete managed address. Once deleted, the address won't be charged in a daily credit usage, but it won't be possible to get the private key for it.

SecurityX-API-Key
Request
path Parameters
id
required
string <uuid>

WalletID of the managed address

Example: 3ad54647-4166-4d34-9186-fd46caaba945
Responses
204

OK

400

Bad Request. Validation failed for the given object in the HTTP Body or Request parameters.

401

Unauthorized. Not valid or inactive subscription key present in the HTTP Header.

500

Internal server error. There was an error on the server during the processing of the request.

delete/v3/custodial/wallet/{id}
Request samples
curl -i -X DELETE \
  'https://api-eu1.tatum.io/v3/custodial/wallet/{id}' \
  -H 'x-api-key: YOUR_API_KEY_HERE'
Response samples
application/json
{
  • "errorCode": "validation.failed",
  • "message": "Request validation failed. Please see data for additional information.",
  • "statusCode": 400,
  • "data": [
    ]
}

Sign and transfer using managed address

2 credits per API call, additional credits are charged for each gas covered operation.


Sign transaction and transfer assets from a custodial managed address.
Supported chains:

  • Solana

Logic for Solana
In Solana, it's possible to cover the fees connected to any arbitrary transaction by a third party. Tatum can cover these fees for any transaction on the Solana blockchain - transfer of SOL, SPL tokens, minting or transferring NFTs or invoking programs. In order to do this, Tatum fee address must be used as a feePayer address during transaction creation:
Mainnet addressDevnet address
AddressDSpHmb7hLnetoybammcJBJiyqMVR3pDhCuW6hqVg9eBF5zPr5331CtBjgVeLedhmJPEpFaUsorLCnb3aCQPsUc9w
Once transaction is constructed using Solana SDK, it can be serialized to HEX data string, which is then passed to the API and signed.
Transaction could require multiple private keys for signing - fee payer, sender of the SOL assets, minting key during NFT mint operation etc. Some of the keys are used in Tatum - fee payer, or, in case of managed wallet holding SOL assets, the key of that managed wallet - those must be referenced in a list of walletIds to be used. For external keys, which are not managed by Tatum, those could either sign the transaction before it's serialization, or could be passed to the API in it's raw form - this is OK only for keys, which could be exposed and there is no harm of loosing assets on them.
Fee payer key is used by default, doesn't have to be mentioned in the list of wallets used for signing.

Examples of different transaction payloads.

1. Send SOL from account HrJtQTy2RW9c6y41RvN8x3bEiD6Co74AuhER2MGCpa58 to FZAS4mtPvswgVxbpc117SqfNgCDLTCtk5CoeAtt58FWU
import { LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction } from '@solana/web3.js'
const from = 'HrJtQTy2RW9c6y41RvN8x3bEiD6Co74AuhER2MGCpa58'
const to = 'FZAS4mtPvswgVxbpc117SqfNgCDLTCtk5CoeAtt58FWU'
const amount = '0.000001'
const devnet_fee_payer = '5zPr5331CtBjgVeLedhmJPEpFaUsorLCnb3aCQPsUc9w'
const fromPubkey = new PublicKey(from)
const transaction = new Transaction({ feePayer: new PublicKey(devnet_fee_payer) })
transaction.add(
  SystemProgram.transfer({
    fromPubkey: fromPubkey,
    toPubkey: new PublicKey(to),
    lamports: new BigNumber(amount).multipliedBy(LAMPORTS_PER_SOL).toNumber(),
  }),
)
transaction.recentBlockhash = '7WyEshBZcZwEbJsvSeGgCkSNMxxxFAym3x7Cuj6UjAUE' // any arbitrary block hash, will be replaced later in the process
return transaction.compileMessage().serialize().toString('hex')
For the above example, developer have 2 options how to sign transaction - if the sender address HrJtQTy2RW9c6y41RvN8x3bEiD6Co74AuhER2MGCpa58 is managed using a Tatum managed wallet with id 0b1eae3d-2520-4903-8bbf-5dec3ad2a5d4, the final payload to the custodial/transaction endpoint should look like this:
{
  "chain": "SOL",
  "txData": "020001044a22af97a838a504e6f7c0b18d779afcea612da50794cc1dac641861fc1ab14afa5cacaf91c298694e64bb5496916c3c68a32affb92d4bcd2736fbb00169d57bd840de2a454960308f688cd3ee308c1fa01ecfa0b03770aaaf3b52d71d46c31d000000000000000000000000000000000000000000000000000000000000000060d38e0da20dc5900b7e902c918eae6a95e2d90af154b53a422f4ab26b050f4f01030201020c02000000e803000000000000",
  "walletIds": [
    {
      "key": "0b1eae3d-2520-4903-8bbf-5dec3ad2a5d4",
      "type": "MANAGED"
    }
  ]
}
If the sender address is not managed, the transaction could be signed with the private key of that address before the serialization and the payload will look like this:
{
  "chain": "SOL",
  "txData": "020001044a22af97a838a504e6f7c0b18d779afcea612da50794cc1dac641861fc1ab14afa5cacaf91c298694e64bb5496916c3c68a32affb92d4bcd2736fbb00169d57bd840de2a454960308f688cd3ee308c1fa01ecfa0b03770aaaf3b52d71d46c31d000000000000000000000000000000000000000000000000000000000000000060d38e0da20dc5900b7e902c918eae6a95e2d90af154b53a422f4ab26b050f4f01030201020c02000000e803000000000000",
  "walletIds": []
}

SecurityX-API-Key
Request
Request Body schema: application/json
chain
required
string

Blockchain to work on

Value: "SOL"
txData
required
string [ 1 .. 500000 ] characters

Hex serialized data representing transaction, which should be signed using one of the managed wallets.

required
Array of objects
Array
key
required
string

Wallet ID of wallet, which should be used for signing. In case of RAW type of the wallet, this represents the private key which will be used for signatures.

type
required
string

Type of the wallet to be used - RAW represents native private key, MANAGED represents ID of the managed wallet.

Enum: "MANAGED" "RAW"
Responses
200

OK

400

Bad Request. Validation failed for the given object in the HTTP Body or Request parameters.

401

Unauthorized. Not valid or inactive subscription key present in the HTTP Header.

500

Internal server error. There was an error on the server during the processing of the request.

post/v3/custodial/transaction
Request samples
application/json
{
  • "chain": "SOL",
  • "txData": "020001044a22af97a838a504e6f7c0b18d779afcea612da50794cc1dac641861fc1ab14afa5cacaf91c298694e64bb5496916c3c68a32affb92d4bcd2736fbb00169d57bd840de2a454960308f688cd3ee308c1fa01ecfa0b03770aaaf3b52d71d46c31d000000000000000000000000000000000000000000000000000000000000000060d38e0da20dc5900b7e902c918eae6a95e2d90af154b53a422f4ab26b050f4f01030201020c02000000e803000000000000",
  • "walletIds": [
    ]
}
Response samples
application/json
{
  • "txId": "c83f8818db43d9ba4accfe454aa44fc33123d47a4f89d47b314d6748eb0e9bc9"
}