Webhooks

TrustVault provides webhooks to alert you of the changes in that status of your transactions. These are POST requests delivered to your server and are sent as soon as an event occurs. The body of the request contains the details of the event.

Upon receiving a webhook notification, it should be acknowledged with a HTTP success response 20x. Otherwise the webhoook notification will be attempted to be sent again according to the following schedule:

  • 1 minute from the previous attempt
  • 2 minutes from the previous attempt
  • 15 minutes from the previous attempt
  • 2 hours from the previous attempt
  • 10 hours from the previous attempt
  • 24 hours from the previous attempt

Events

Event Description
Bitcoin Received A bitcoin wallet belonging to the trustId has received a transaction
Ethereum Received An ethereum wallet belonging to the trustId has received a ETH or ERC20 transaction

Event Object

Attribute Description
messageId string
Unique identifier for the webhook notification
version string
The webhook version
type string
The webhook notification type - BITCOIN_TRANSACTION_RECEIVED/ETHEREUM_TRANSACTION_RECEIVED
timestamp integer
The timestamp of the webhook notification
isoTimestamp string
The timestamp of the webhook notification in ISO 8601 format
payload object
The payload for the webhook notification

Bitcoin Received Event

The bitcoin received webhoook will be triggered as soon as there is 1 confirmation from a miner.

Bitcoin Received Payload

Attribute Description
trustId string
Unique identifier for the TrustVault user
subWalletId object
Unique identifier for the wallet
subWalletIdString string
Unique identifier for the wallet, in string format
transactionAmount string
The transaction amount in satoshi (integer string)
bitcoinAddress string
The UTXO receive address of the transaction
transactionType string
The type of transaction - RECEIVED
blockHeight integer
The block number where the transaction was included in
transactionId string
Unique identifier for the transaction in the blockchain
transactionBlockTime integer
The timestamp of the block
transactionAmountInBtc string
The transaction amount in BTC (float string)

Ethereum Received Event

The ethereum received webhoook will be triggered as soon as there is 1 confirmation from a miner.

Ether/ERC20 Transfer Received Payload

Attribute Description
trustId string
Unique identifier for the TrustVault user
subWalletId object
Unique identifier for the wallet
subWalletIdString string
Unique identifier for the wallet, in string format
from string
Ethereum address where the transaction was sent from
to string
Ethereum address where the transaction was sent to (*)
transactionValue string
Transaction value in Wei
transactionValueInEth string
Transaction value in Eth
transactionType string
The type of transaction - RECEIVED/SELF
tokensData array
Token data (see token structure below) (**)
transactionId string
Unique identifier for the transaction in the blockchain
blockHeight string
The block number where the transaction was included in
gasUsed string
Gas used by the transaction
gasPrice string
Gas price of the transaction
transactionBlockTime number
The timestamp of the block

(*)

  • In Ether transfers, to has the value of ethereum address where the Ether is transferred to.
  • In ERC20 transfers, to has the value of smart contract that manages the token transfer.

(**)

  • In Ether transfers, this array will be empty.

Token data

Attribute Description
to string
Ethereum address where the tokens were transferred to
quantity string
Quantity of tokens transferred
symbol string
Token symbol
assetName string
Name of the token
tokenDirectionType string
Direction of token transfer - RECEIVED/SELF

Sub Wallet ID object

Attribute Description
id string
Unique identifier for the HD Wallet
type string
The chain identifier where the sub wallet belongs to (“BTC”, “BINANCE”)
index number
Index of the sub wallet in the HD Wallet starting at zero (integer)

Sample Bitcoin Received Event Object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"messageId": "87f49826-dafb-46e9-a9bc-6ed7ef61f811",
"version": "1.0.1",
"type": "BITCOIN_TRANSACTION_RECEIVED",
"timestamp": 1588323320463,
"isoTimestamp": "2020-05-01T09:18:31.354Z",
"payload": {
"trustId": "f67ddcf6-e95d-4aa7-9a2d-e855ba5dc380",
"subWalletId": {
"id": "f63b2ff1-f02b-48df-8b9f-bc57f5c57061",
"type": "BTC",
"index": 0,
},
"transactionAmount": "142498030",
"bitcoinAddress": "342ftSRCvFHfCeFFBuz4xwbeqnDw6BGUey",
"transactionType": "RECEIVED",
"blockHeight": 627997,
"transactionId": "97f1f9150a992ac5309a0837ef3309757dc6359b8355867933d693b7c6a1ae98",
"transactionBlockTime": 1588078790,
"transactionAmountInBtc": "1.4249803",
}
}

Sample Ether Received Event Object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"version": "1.0.0",
"type": "ETHEREUM_TRANSACTION_RECEIVED",
"payload": {
"trustId": "59ed6b8e-04f8-4815-ae59-f5e897ba3783",
"transactionValue": "2200000000000000",
"transactionValueInEth": "0.0022",
"transactionType": "RECEIVED",
"tokensData": [],
"transactionId": "0x657866589816879098d2c0644c832cb772f091929e714033e1123bdb35587a15",
"blockHeight": "8562864",
"from": "0xEfdF561eB7eB03BF1A2e52466F7A3628a9Bb94ec",
"to": "0xe191edfa3ea87452857e81ebc744d3d94d103bc0",
"gasUsed": "21000",
"gasPrice": "102000000000",
"subWalletId": {
"id": "d11710e5-9354-4a28-accd-7e45f77f2b83",
"type": "ETH",
"index": 0
},
"subWalletIdString": "d11710e5-9354-4a28-accd-7e45f77f2b83/ETH/0",
"transactionBlockTime": 1598363384
},
"messageId": "4cfe6535-959b-4759-a9a2-043242e2ff57",
"timestamp": 1598363410185,
"isoTimestamp": "2020-08-25T13:50:10.185Z"
}

Sample ERC20 Received Event Object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
"version": "1.0.0",
"type": "ETHEREUM_TRANSACTION_RECEIVED",
"payload": {
"trustId": "59ed6b8e-04f8-4815-ae59-f5e897ba3783",
"transactionValue": "0",
"transactionValueInEth": "0",
"transactionType": "RECEIVED",
"tokensData": [
{
"to": "0xe191edfa3ea87452857e81ebc744d3d94d103bc0",
"quantity": "11.22",
"symbol": "USDT",
"assetName": "Tether USD",
"tokenDirectionType": "RECEIVED"
}
],
"transactionId": "0x953090cc45568e88963de8c394dee14ee152936c4216441380186e5d19f4e6cf",
"blockHeight": "8562794",
"from": "0x16d27cf6a6cfe5b0ede09e4148a4c5c082577b3e",
"to": "0x786bae3ca30e6a7019eb11abfa22d81f0febdce6",
"gasUsed": "41194",
"gasPrice": "100000000000",
"subWalletId": {
"id": "d11710e5-9354-4a28-accd-7e45f77f2b83",
"type": "ETH",
"index": 0
},
"subWalletIdString": "d11710e5-9354-4a28-accd-7e45f77f2b83/ETH/0",
"transactionBlockTime": 1598362450
},
"messageId": "e04d3c44-8ba2-4403-bc20-8564af6d3939",
"timestamp": 1598362511233,
"isoTimestamp": "2020-08-25T13:35:11.233Z"
}

Webhook Security

Webhook notifications should be verified using the message hash signature in the header and the secret key to prevent attackers from imitating valid webhooks.

Each webhook is associated with a single secret key, which is given upon registration of the webhook. The secret key is used to generate an HMAC using SHA-256 hash algorithm.

Webhook notifications will have an X-Sha2-Signature header in the request, containing the HMAC. The secret key should be used to compute the message hash signature using the complete event object. You must ensure that the generated hash signature matches the X-Sha2-Signature header sent by TrustVault.

Verifying HMAC-256 signature

1
2
3
4
5
6
7
8
9
10
11
12
13
import * as crypto from "crypto";

// NOTE: Do not hard code your secret key. Store it somewhere safe
const secretKey = "SECRET_KEY";
const hmac = crypto.createHmac("SHA256", secretKey);

// Compute the hash from the stringified JSON request.body
const computedHashSignature = hmac.update(request.body).digest("hex");
const expectedHashSignature = request.headers["X-Sha2-Signature"];

if (computedHashSignature !== expectedHashSignature) {
throw new Error("Webhook hash signature mismatch");
}

Handle Duplicate Events

Webhook endpoints might occasionally receive the same event more than once. In particular, during chain re-organisation a webhook event could be re-sent for the exact same transaction. We advise you to guard against duplicated event receipts by making your event processing idempotent.