Webhook Usage
Use Case
Webhooks provide one-way communication between the Custody Infrastructure backend and your company's software. They are event-driven and, when triggered, send HTTP calls from the mandatory cosigner to your business logic server. You can configure Custody Infrastructure webhooks to automatically notify your system whenever:
- Input Transaction: A deposit is received
- Output Transaction: An outbound transaction changes status
- Alert Balance: The account balance changes
- Approve Transaction: A transaction is approved
All of the webhooks take narrowing parameters, such as account, currency, amount thresholds, etc.
The Four Types and their Filters
Input Transaction
An input transaction is any transaction where the monitored account receives assets. It filters transactions by:
- CoinSymbol: What asset are you monitoring?
- Machine: What machine is receiving the funds, Cold Vault or MPC?
- AccountIds: You can monitor multiple accounts with a single webhook; which ones do you want alerts for?
- MinAmount: Let's not bother with small change. How much does an account need to receive in a single transaction to be worth notifying you?
- Confirmations: How locked into the blockchain must a transaction be before you're told about it? You can supply up to ten values here.
The above filters are mandatory for every input transaction webhook.
Output Transaction
An output transaction is any transaction where the monitored account attempts to send assets. It filters transactions by:
- AlertEvent: This filter may optionally include CoinSymbol, Machine, and AccountIds as detailed in Input Transaction; it requires that an AlertEvent be specified. This event can be any one of the following:
- "No funds available"
- "Created"
- "Failed-Limits"
- "Failed-Technical"
- "Sent"
- "Timeout occurred"
- "Waiting to be processed"
- "Canceled"
- "Waiting for external co-signer"
- "Failed-Policy"
- Confirmations: This filter may optionally include CoinSymbol, Machine, AccountIds; it requires that Confirmations (as detailed in Input Transaction) be specified.
Alert balance
The alert balance webhook only monitors the main wallet of each specified account. It lets you know whenever a balance crosses a selected threshold. You can optionally use the AlertEvent filter to specify whether you get notified only when the threshold is crossed in a specific direction. It takes the following filters:
- CoinSymbol: What asset are you monitoring?
- Threshold: When do you want to be notified?
The above filters are mandatory for every Alert Balance webhook. The webhook may be further refined with the addition of any of the following optional filters:
- Machine: What machine is receiving the funds, Cold Vault or MPC?
- AccountIds: You can monitor multiple accounts with a single webhook; which ones do you want alerts for?
- AlertEvents: This can be either "Below" or "Above" and will cause the webhook to send an alert only when the threshold is crossed in the specified direction.
Approve Transaction
This event cannot be filtered. It will alert the listener whenever a transaction is approved.
API Functionality
The Custody Infrastructure API allows you to easily:
- /registerWebhook - Configure a new webhook to connect between the systems
- /getAllWebhooks - View a list of all configured webhooks
- /unregisterWebhook - Remove a webhook and stop it from sending further signals
Usage
Preparation
Prior to registering your webhooks in the Custody Infrastructure system, make sure you have your software (the "Listener machine") ready to receive the webhooks.
Make note of the addresses on your end. You need them when registering the webhooks so they get sent to the right place.
The examples shown use HTTP. To secure the webhooks, HTTPS is also supported.
Registration
Create a Webhook using registerWebhook. You can see the documentation in /registerWebhook.

As an example:
registerWebhook("http://<your ip: port>", 0, filter= {"CoinSymbol": "ETH", "Machine": "Hot", "AccountIds": ["1"], "MinAmount": "100000000000"})Run the Webhook as follows:
import http.client
from sys import argv
from http.server import BaseHTTPRequestHandler, HTTPServer
import http
import json
import logging
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
WEBHOOK_FILE_NAME = "webhooks.json"
class ServerHandler(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super(ServerHandler, self).__init__(*args, **kwargs)
self.data_string = None
def _set_headers(self, status_code):
self.send_response(status_code)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_HEAD(self):
self._set_headers(http.HTTPStatus.OK)
def do_POST(self):
try:
self.data_string = self.rfile.read(int(self.headers['Content-Length']))
data = json.loads(self.data_string)
logging.info("Loaded data")
with open(WEBHOOK_FILE_NAME, "a") as outfile:
outfile.write(json.dumps(data) + "\n")
logging.info("Loaded dump: {}".format(data))
self._set_headers(http.HTTPStatus.OK)
except Exception as e:
logging.error("Failed to handle POST request. Exception: %s" % e)
self._set_headers(http.HTTPStatus.BAD_REQUEST)
def run(port=8080):
server_address = ('', port)
server = HTTPServer(server_address, ServerHandler)
logging.info('Starting server')
server.serve_forever()
if __name__ == "__main__":
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()
Check your incoming notifications at your prepared destination. For example, if you desire notifications for Ethereum transactions, the server will print the following when receiving one:
2024-04-19 19:16:27,583 INFO Loaded data
2024-04-19 19:16:27,584 INFO Loaded dump:
[
{
"Account":"Main Account",
"AccountId":"1",
"Amount":"300000000000000000",
"Confirmations":"297931",
"Currency":"ETH",
"Date":"2024-03-05 23:56:12.000",
"ExtraData":[
{
"ExtraDataForKey":[
],
"Key":"AccountId",
"Value":"1"
},
{
"ExtraDataForKey":[
],
"Key":"Amount",
"Value":"300000000000000000"
},
{
"ExtraDataForKey":[
],
"Key":"Confirmations",
"Value":"297931"
},
{
"ExtraDataForKey":[
],
"Key":"Date",
"Value":"2024-03-05 23:56:12.000"
},
{
"ExtraDataForKey":[
],
"Key":"From",
"Value":"0xfb89146eFA99cCB83e7C6eF51C7105844EA30e26"
},
{
"ExtraDataForKey":[
],
"Key":"In/Out",
"Value":"In"
},
{
"ExtraDataForKey":[
],
"Key":"Status",
"Value":"Input Transaction"
},
{
"ExtraDataForKey":[
],
"Key":"To",
"Value":"0x609e925deAe3520e0f5c05FFee6dFb0110a09410"
},
{
"ExtraDataForKey":[
],
"Key":"User Description",
"Value":""
},
{
"ExtraDataForKey":[
],
"Key":"Currency",
"Value":"Ethereum (symbol: ETH)"
},
{
"ExtraDataForKey":[
],
"Key":"Account",
"Value":"Main Account (id: 1)"
},
{
"ExtraDataForKey":[
],
"Key":"Transaction Type",
"Value":"Ethereum Transaction"
},
{
"ExtraDataForKey":[
{
"Key":"Address of Source 1",
"Value":"0xfb89146eFA99cCB83e7C6eF51C7105844EA30e26"
},
{
"Key":"Contact Name of Source 1",
"Value":""
},
{
"Key":"Contact Machine of Source 1",
"Value":""
},
{
"Key":"Wallet Id of Source 1",
"Value":""
}
],
"Key":"Sources",
"Value":"1"
},
{
"ExtraDataForKey":[
{
"Key":"Address of Destination 1",
"Value":"0x609e925deAe3520e0f5c05FFee6dFb0110a09410"
},
{
"Key":"Contact Name of Destination 1",
"Value":""
},
{
"Key":"Contact Machine of Destination 1",
"Value":""
},
{
"Key":"Wallet Id of Destination 1",
"Value":""
},
{
"Key":"Amount to Destination 1",
"Value":"300000000000000000"
}
],
"Key":"Amount to Destinations",
"Value":"300000000000000000"
},
{
"ExtraDataForKey":[
],
"Key":"Machine",
"Value":"MPC"
},
{
"ExtraDataForKey":[
],
"Key":"Gas Price",
"Value":"1904558343"
},
{
"ExtraDataForKey":[
],
"Key":"Max Priority Fee",
"Value":"-"
},
{
"ExtraDataForKey":[
],
"Key":"Gas Limit",
"Value":"21000"
},
{
"ExtraDataForKey":[
],
"Key":"Gas Used",
"Value":"21000"
},
{
"ExtraDataForKey":[
],
"Key":"Total Fee",
"Value":"39995725203000"
},
{
"ExtraDataForKey":[
],
"Key":"TxId",
"Value":"0x4ea66e134235766c94e6c5f3544dc6286e18c31fe656236ce1ac26243c21142f"
},
{
"ExtraDataForKey":[
],
"Key":"Block Number",
"Value":"1080418"
}
],
"From":"0xfb89146eFA99cCB83e7C6eF51C7105844EA30e26",
"In/Out":"In",
"Number":0,
"Status":"Input Transaction",
"To":"0x609e925deAe3520e0f5c05FFee6dFb0110a09410",
"TxId":"0x4ea66e134235766c94e6c5f3544dc6286e18c31fe656236ce1ac26243c21142f",
"User Description":""
}
]
1.1.1.11 - - [19/Apr/2024 19:16:27] "POST / HTTP/1.1" 200 -Further Reading
See the technical side of registering a webhook at /registerWebhook.
Learn what information properly-configured webhook output can include in Webhook v2 Output .
Wow, webhooks send a lot of sensitive data over the network. Read Securing Webhook Communications to learn how to secure your webhook data in flight.
Check your current webhook configuration by running /getAllWebhooks .
Remove unnecessary webhooks by running /unregisterWebhook .