Webhooks are critical for real-time notifications within our Layer1 platform, enabling automated updates related to payments, conversions, or new address creation events. When such events occur, Layer1 makes an HTTP request to the URL configured by the user for the webhooks.
Acknowledging Webhooks
The Layer1 webhooks service expects to receive a 200 HTTP status code as an acknowledgment of a successfully received and validated webhook. This response should be sent immediately upon receipt of the webhook to confirm its delivery and avoid timeout errors.
Webhook retry policy
If BVNK does not receive a 200 status code, the webhook retry policy will kick in.
The retry policy adds a delay before each retry, starting with a base delay and increasing the time between retries. The delay grows larger after each attempt, but will not exceed 15 minutes. The system will attempt up to 100 times, and after that, no further retries will occur.
Webhook Validation
Webhooks include an x-signature header, which enables servers to authenticate the request using a secret key specific to your server setup.
Signature Calculation with ECDSA
The process to calculate and verify the signature using ECDSA
Capture the raw payloadDo not parse the incoming HTTP request into an object or re-serialize it. Instead, capture the raw payload as a string to ensure that the signature verification process is accurate.
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
public class JavaSignatureExample {
public static void main(String[] args) throws Exception {
// If you don't already have BouncyCastle as a provider, add it
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
// Public key provided from webhook configuration
String publicKeyBase64 = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAExn8LhKa3YnVvGHeyT+siyu9+B5knDRtigP4R08nw7Fp0lbXtwoiAO1N0LOj7k39JY5iM385BJrRV2u5Y4N0Qxg==";
// From X-Signature header
String signatureBase64 = "MEYCIQCtvKgMTivqsT3S2G3qD46lK0+FD7ECW4dK2MtaivfWvwIhALJly6ZqemabK+gYGNWpZACzj1ApJ6immVuIQ0MxONXV";
// Body of the request
String body = "hello world";
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.decode(publicKeyBase64));
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initVerify(publicKey);
// The body of the request
signature.update(body.getBytes());
boolean verified = signature.verify(Base64.decode(signatureBase64));
System.out.println("Signature is valid: " + verified);
}
}<?php
function verifyECDSASignatureExample(): bool
{
// Example data embedded in the function
$publicKeyBase64 = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAExn8LhKa3YnVvGHeyT+siyu9+B5knDRtigP4R08nw7Fp0lbXtwoiAO1N0LOj7k39JY5iM385BJrRV2u5Y4N0Qxg==";
$signatureBase64 = "MEYCIQCtvKgMTivqsT3S2G3qD46lK0+FD7ECW4dK2MtaivfWvwIhALJly6ZqemabK+gYGNWpZACzj1ApJ6immVuIQ0MxONXV";
$message = "hello world";
try {
// Decode the base64-encoded public key
$publicKeyDer = base64_decode($publicKeyBase64);
if ($publicKeyDer === false) {
throw new Exception("Failed to decode public key");
}
// Create a PEM-formatted public key from the DER data
$publicKeyPem = "-----BEGIN PUBLIC KEY-----\n" .
chunk_split(base64_encode($publicKeyDer), 64, "\n") .
"-----END PUBLIC KEY-----\n";
// Load the public key
$publicKey = openssl_pkey_get_public($publicKeyPem);
if ($publicKey === false) {
throw new Exception("Failed to load public key: " . openssl_error_string());
}
// Decode the signature
$signature = base64_decode($signatureBase64);
if ($signature === false) {
throw new Exception("Failed to decode signature");
}
// Verify the signature
$result = openssl_verify($message, $signature, $publicKey, OPENSSL_ALGO_SHA256);
// Clean up
openssl_free_key($publicKey);
if ($result === 1) {
echo "Signature verification succeeded!\n";
return true;
} elseif ($result === 0) {
echo "Signature verification failed!\n";
return false;
} else {
throw new Exception("Error during signature verification: " . openssl_error_string());
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
return false;
}
}
// Run the example
verifyECDSASignatureExample();
?>from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
import base64
# Replace this with your webhook public key
public_key_base64 = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAExn8LhKa3YnVvGHeyT+siyu9+B5knDRtigP4R08nw7Fp0lbXtwoiAO1N0LOj7k39JY5iM385BJrRV2u5Y4N0Qxg=="
# This comes from X-Signature header
signature_base64 = "MEYCIQCtvKgMTivqsT3S2G3qD46lK0+FD7ECW4dK2MtaivfWvwIhALJly6ZqemabK+gYGNWpZACzj1ApJ6immVuIQ0MxONXV"
# This is the body of the request sent to you
message = b"hello world"
# Load the public key from the base64-encoded string
public_key_loaded = serialization.load_der_public_key(
base64.b64decode(public_key_base64)
)
# Verify the signature using the loaded public key
try:
public_key_loaded.verify(
base64.b64decode(signature_base64),
message,
ec.ECDSA(hashes.SHA256())
)
print("\nSignature verification succeeded!")
except InvalidSignature:
print("\nSignature verification failed!")Webhooks
layer1:crypto:address:created
The webhook notification sends a JSON object containing details about the event. Here is an example payload:
{
"event": "layer1:crypto:address:created",
"timestamp": "2024-04-30T15:57:30.399031710Z",
"data": {
"id": "37729aed-4e03-46d5-b695-d964da0ae29e",
"address": "0x157e511931f57d7d41d098b5bebcf8ebfc2b87d8",
"network": "ETHEREUM",
"keyPairId": "85cbb05e-8ffe-4b09-ba7d-4c41dfeb551c",
"reference": "d427cc5f-20d1-4e6d-93b0-454a6cb45cd8",
"assetPoolId": "e0579d29-987a-440c-b78b-26067b49bc96"
}
}Below is a detailed explanation of each field in the webhook payload:
| Field | Type | Description |
|---|---|---|
event | string | Identifies the type of event. Example: "layer1:crypto:address:created" |
timestamp | string | ISO 8601 formatted date and time when the event was generated. |
data | object | Contains detailed information about the event. |
data.id | string | Unique identifier for the event, in GUID format. |
data.address | string | The cryptocurrency address that was created. |
data.network | string | The network for the cryptocurrency address. |
data.keyPairId | string | Identifier for the key pair associated with the address, in GUID format. |
data.reference | string | A reference identifier linked to the creation of this address, in GUID format. |
data.assetPoolId | string | Identifier of the asset pool this address was added to, in GUID format. |
layer1:crypto:deposit:status-change
The webhook notification sends a JSON object containing details about the event. Here is the example payloads:
{
event: "layer1:crypto:deposit:status-change",
timestamp: "2024-05-01T11:55:23.676068369Z",
data: {
id: "018f3402631176798ab2d431929f53b938d51d4b3ef64c809cb73eb884cc7c306f",
address: {
id: "38d51d4b-3ef6-4c80-9cb7-3eb884cc7c30",
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
assetPoolId: "e0579d29-987a-440c-b78b-26067b49bc96",
network: "ETHEREUM",
keyPairId: "173cfb47-3ce1-4550-98bc-2da2f1cb866b",
reference: "fcd4687e-5bc7-41e0-ba5a-d2f13a857ee7",
},
reference: null,
status: "DETECTED",
sources: [
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.001",
},
],
destinations: [
{
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
amount: "0.001",
},
],
type: "DEPOSIT",
asset: "ETH",
amount: "0.001",
hash: "0x5fee8f91e72d6baba7b95af5a031ea3b3e1ae527009f401b5403a3c2f3294530",
networkDetail: null,
metadata: null,
createdAt: "2024-05-01T11:55:22.769Z",
updatedAt: "2024-05-01T11:55:23.545773Z",
},
};{
event: "layer1:crypto:deposit:status-change",
timestamp: "2024-05-01T11:55:28.579411700Z",
data: {
id: "018f3402631176798ab2d431929f53b938d51d4b3ef64c809cb73eb884cc7c306f",
address: {
id: "38d51d4b-3ef6-4c80-9cb7-3eb884cc7c30",
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
assetPoolId: "e0579d29-987a-440c-b78b-26067b49bc96",
network: "ETHEREUM",
keyPairId: "173cfb47-3ce1-4550-98bc-2da2f1cb866b",
reference: "fcd4687e-5bc7-41e0-ba5a-d2f13a857ee7",
},
reference: null,
status: "UNCONFIRMED",
sources: [
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.000038485390062",
},
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.001",
},
],
destinations: [
{
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
amount: "0.001",
},
],
type: "DEPOSIT",
asset: "ETH",
amount: "0.001",
hash: "0x5fee8f91e72d6baba7b95af5a031ea3b3e1ae527009f401b5403a3c2f3294530",
networkDetail: {
block: { number: 5814953, timestamp: "2024-05-01T11:55:24Z" },
fee: { amount: "0.000038485390062", asset: "ETH" },
},
metadata: null,
createdAt: "2024-05-01T11:55:22.769Z",
updatedAt: "2024-05-01T11:55:28.535125Z",
},
};{
event: "layer1:crypto:deposit:status-change",
timestamp: "2024-05-01T11:55:28.579411700Z",
data: {
id: "018f3402631176798ab2d431929f53b938d51d4b3ef64c809cb73eb884cc7c306f",
address: {
id: "38d51d4b-3ef6-4c80-9cb7-3eb884cc7c30",
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
assetPoolId: "e0579d29-987a-440c-b78b-26067b49bc96",
network: "ETHEREUM",
keyPairId: "173cfb47-3ce1-4550-98bc-2da2f1cb866b",
reference: "fcd4687e-5bc7-41e0-ba5a-d2f13a857ee7",
},
reference: null,
status: "CONFIRMED",
sources: [
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.000038485390062",
},
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.001",
},
],
destinations: [
{
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
amount: "0.001",
},
],
type: "DEPOSIT",
asset: "ETH",
amount: "0.001",
hash: "0x5fee8f91e72d6baba7b95af5a031ea3b3e1ae527009f401b5403a3c2f3294530",
networkDetail: {
block: { number: 5814953, timestamp: "2024-05-01T11:55:24Z" },
fee: { amount: "0.000038485390062", asset: "ETH" },
},
metadata: null,
createdAt: "2024-05-01T11:55:22.769Z",
updatedAt: "2024-05-01T11:55:28.535125Z",
},
};{
event: "layer1:crypto:deposit:status-change",
timestamp: "2024-05-01T11:56:29.064464799Z",
data: {
id: "018f3402631176798ab2d431929f53b938d51d4b3ef64c809cb73eb884cc7c306f",
address: {
id: "38d51d4b-3ef6-4c80-9cb7-3eb884cc7c30",
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
assetPoolId: "e0579d29-987a-440c-b78b-26067b49bc96",
network: "ETHEREUM",
keyPairId: "173cfb47-3ce1-4550-98bc-2da2f1cb866b",
reference: "fcd4687e-5bc7-41e0-ba5a-d2f13a857ee7",
},
reference: null,
status: "SCREENING_REQUESTED",
sources: [
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.000038485390062",
},
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.001",
},
],
destinations: [
{
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
amount: "0.001",
},
],
type: "DEPOSIT",
asset: "ETH",
amount: "0.001",
hash: "0x5fee8f91e72d6baba7b95af5a031ea3b3e1ae527009f401b5403a3c2f3294530",
networkDetail: {
block: { number: 5814953, timestamp: "2024-05-01T11:55:24Z" },
fee: { amount: "0.000038485390062", asset: "ETH" },
},
metadata: null,
createdAt: "2024-05-01T11:55:22.769Z",
updatedAt: "2024-05-01T11:56:28.994764Z",
},
};{
event: "layer1:crypto:deposit:status-change",
timestamp: "2024-05-01T11:56:36.625504360Z",
data: {
id: "018f3402631176798ab2d431929f53b938d51d4b3ef64c809cb73eb884cc7c306f",
address: {
id: "38d51d4b-3ef6-4c80-9cb7-3eb884cc7c30",
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
assetPoolId: "e0579d29-987a-440c-b78b-26067b49bc96",
network: "ETHEREUM",
keyPairId: "173cfb47-3ce1-4550-98bc-2da2f1cb866b",
reference: "fcd4687e-5bc7-41e0-ba5a-d2f13a857ee7",
},
reference: null,
status: "SUCCESS",
sources: [
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.000038485390062",
},
{
address: "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
amount: "0.001",
},
],
destinations: [
{
address: "0xf6483454996bce404d62656eb3cbcf87232dc153",
amount: "0.001",
},
],
type: "DEPOSIT",
asset: "ETH",
amount: "0.001",
hash: "0x5fee8f91e72d6baba7b95af5a031ea3b3e1ae527009f401b5403a3c2f3294530",
networkDetail: {
block: { number: 5814953, timestamp: "2024-05-01T11:55:24Z" },
fee: { amount: "0.000038485390062", asset: "ETH" },
},
metadata: null,
createdAt: "2024-05-01T11:55:22.769Z",
updatedAt: "2024-05-01T11:56:36.513590Z",
},
};Below is a detailed explanation of each field in the webhook payload:
| Field | Type | Description |
|---|---|---|
event | string | Identifies the type of event. Example: "layer1:crypto:deposit:status-change" |
timestamp | string | ISO 8601 formatted date and time when the event was generated. |
data | object | Contains detailed information about the event. |
data.id | string | Unique identifier for the event. |
data.address | object | Detailed information about the address involved in the deposit. |
data.address.id | string | Unique identifier for the address object, in GUID format. |
data.address.address | string | The cryptocurrency address involved. |
data.address.assetPoolId | string | Identifier of the asset pool this address belongs to, in GUID format. |
data.address.network | string | The network for the cryptocurrency address |
data.address.keyPairId | string | Identifier for the key pair associated with the address, in GUID format. |
data.address.reference | string | A reference identifier linked to the creation of this address. |
data.reference | null/string | A general reference identifier, can be null. |
data.status | string | Current status of the deposit [DETECTED, UNCONFIRMED, CONFIRMED, SCREENING_REQUESTED, SUCCESS]. |
data.sources[] | array | Array of source addresses and amounts involved in the transaction. |
data.destinations[] | array | Array of destination addresses and amounts involved in the transaction. |
data.type | string | Type of transaction. |
data.asset | string | Type of asset involved in the transaction. |
data.amount | string | Amount of the asset involved in the transaction. |
data.hash | string | Transaction hash. |
data.networkDetail | null | Additional network-specific details, can be null. |
data.metadata | null | Additional metadata related to the event, can be null. |
data.createdAt | string | ISO 8601 formatted date and time when the data was created. |
data.updatedAt | string | ISO 8601 formatted date and time when the data was last updated. |
layer1:crypto:withdrawal:status-change
The webhook notification sends a JSON object containing details about the event. Here is the example payloads:
{
"event": "layer1:crypto:withdrawal:status-change",
"timestamp": "2024-05-01T14:58:57.756642777Z",
"data": {
"id": "018f34aa753176e1a746377665057346aa2eadaf62374e3fb43529de7c4be91969",
"address": {
"id": "aa2eadaf-6237-4e3f-b435-29de7c4be919",
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"assetPoolId": "e0579d29-987a-440c-b78b-26067b49bc96",
"network": "ETHEREUM",
"keyPairId": "a2dabc1a-9b36-40dd-b236-2e542fec155c",
"reference": "085aa928-01b6-407b-82d8-2b9975cbc250"
},
"reference": "28b262d9-1f52-4ee2-9f94-addd9762d23c",
"status": "CREATED",
"sources": [
{
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"amount": "0.000117806730763928"
},
{
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"amount": "0.001"
}
],
"destinations": null,
"type": "WITHDRAWAL",
"asset": "ETH",
"amount": "0.001",
"hash": null,
"networkDetail": null,
"metadata": null,
"createdAt": "2024-05-01T14:58:57.457Z",
"updatedAt": "2024-05-01T14:58:57.736442Z"
}
}{
"event": "layer1:crypto:withdrawal:status-change",
"timestamp": "2024-05-01T14:58:58.491311736Z",
"data": {
"id": "018f34aa753176e1a746377665057346aa2eadaf62374e3fb43529de7c4be91966",
"address": {
"id": "aa2eadaf-6237-4e3f-b435-29de7c4be919",
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"assetPoolId": "e0579d29-987a-440c-b78b-26067b49bc96",
"network": "ETHEREUM",
"keyPairId": "a2dabc1a-9b36-40dd-b236-2e542fec155c",
"reference": "085aa928-01b6-407b-82d8-2b9975cbc250"
},
"reference": "28b262d9-1f52-4ee2-9f94-addd9762d23c",
"status": "SIGNED",
"sources": [
{
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"amount": "0.000117806730763928"
},
{
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"amount": "0.001"
}
],
"destinations": null,
"type": "WITHDRAWAL",
"asset": "ETH",
"amount": "0.000117806730763928",
"hash": null,
"networkDetail": null,
"metadata": null,
"createdAt": "2024-05-01T14:58:57.457Z",
"updatedAt": "2024-05-01T14:58:58.366656Z"
}
}{
"event": "layer1:crypto:withdrawal:status-change",
"timestamp": "2024-05-01T14:59:02.359359108Z",
"data": {
"id": "018f34aa753176e1a746377665057346aa2eadaf62374e3fb43529de7c4be91969",
"address": {
"id": "aa2eadaf-6237-4e3f-b435-29de7c4be919",
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"assetPoolId": "e0579d29-987a-440c-b78b-26067b49bc96",
"network": "ETHEREUM",
"keyPairId": "a2dabc1a-9b36-40dd-b236-2e542fec155c",
"reference": "085aa928-01b6-407b-82d8-2b9975cbc250"
},
"reference": "28b262d9-1f52-4ee2-9f94-addd9762d23c",
"status": "UNCONFIRMED",
"sources": [
{
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"amount": "0.000114500286264"
},
{
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"amount": "0.001"
}
],
"destinations": [
{
"address": "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
"amount": "0.001"
}
],
"type": "WITHDRAWAL",
"asset": "ETH",
"amount": "0.001",
"hash": "0xb0d49a30ebe1c84e89a89c52579ae06639dc22d39fd8bb91bfa6dc0130bd09ae",
"networkDetail": {
"block": {
"number": 5815735,
"timestamp": "2024-05-01T14:59:00Z"
},
"fee": {
"amount": "0.000114500286264",
"asset": "ETH"
}
},
"metadata": null,
"createdAt": "2024-05-01T14:58:57.457Z",
"updatedAt": "2024-05-01T14:59:02.331458Z"
}
}{
"event": "layer1:crypto:withdrawal:status-change",
"timestamp": "2024-05-01T14:59:50.096614363Z",
"data": {
"id": "018f34aa753176e1a746377665057346aa2eadaf62374e3fb43529de7c4be91966",
"address": {
"id": "aa2eadaf-6237-4e3f-b435-29de7c4be919",
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"assetPoolId": "e0579d29-987a-440c-b78b-26067b49bc96",
"network": "ETHEREUM",
"keyPairId": "a2dabc1a-9b36-40dd-b236-2e542fec155c",
"reference": "085aa928-01b6-407b-82d8-2b9975cbc250"
},
"reference": "28b262d9-1f52-4ee2-9f94-addd9762d23c",
"status": "CONFIRMED",
"sources": [
{
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"amount": "0.000114500286264"
},
{
"address": "0x2ec9ded3d63d2d9c30b72c31d267e207d7242394",
"amount": "0.001"
}
],
"destinations": [
{
"address": "0xae9e8a1235e1113f936a38492c70fbb4ee297cdb",
"amount": "0.001"
}
],
"type": "WITHDRAWAL",
"asset": "ETH",
"amount": "0.000114500286264",
"hash": "0xb0d49a30ebe1c84e89a89c52579ae06639dc22d39fd8bb91bfa6dc0130bd09ae",
"networkDetail": {
"block": {
"number": 5815735,
"timestamp": "2024-05-01T14:59:00Z"
},
"fee": {
"amount": "0.000114500286264",
"asset": "ETH"
}
},
"metadata": null,
"createdAt": "2024-05-01T14:58:57.457Z",
"updatedAt": "2024-05-01T14:59:50.060099Z"
}
}Below is a detailed explanation of each field in the webhook payload:
| Field | Type | Description |
|---|---|---|
event | string | Identifies the type of event, e.g., "layer1:crypto:withdrawal:status-change" |
timestamp | string | ISO 8601 formatted date and time when the event was generated. |
data | object | Contains detailed information about the event. |
data.id | string | Unique identifier for the event. |
data.address | object | Details of the address involved in the withdrawal. |
data.address.id | string | Unique identifier for the address object. |
data.address.address | string | The cryptocurrency address involved. |
data.address.assetPoolId | string | Identifier of the asset pool this address belongs to, in GUID format. |
data.address.network | string | The network for the cryptocurrency address. |
data.address.keyPairId | string | Identifier for the key pair associated with the address, in GUID format. |
data.address.reference | string | A reference identifier linked to the address. |
data.reference | string | A general reference identifier for the withdrawal. |
data.status | string | Current status of the withdrawal [CREATED, SIGNED,UNCONFIRMED, CONFIRMED]. |
data.sources[] | array | Array of source addresses and amounts involved in the withdrawal. |
data.destinations[] | array | Array of destination addresses and amounts being transferred. |
data.type | string | Type of transaction. |
data.asset | string | Type of asset involved in the transaction. |
data.amount | string | Total amount of the asset being withdrawn. |
data.hash | string | Transaction hash. |
data.networkDetail | object | Additional details about the network state at the time of the transaction. |
data.networkDetail.block | object | Block information relevant to the transaction. |
data.networkDetail.block.number | string | Block number associated with the transaction. |
data.networkDetail.block.timestamp | string | Timestamp of the block. |
data.networkDetail.fee | object | Fee information related to the transaction. |
data.networkDetail.fee.amount | string | Amount of the fee charged. |
data.networkDetail.fee.asset | string | Asset type of the fee (e.g., ETH). |
data.metadata | null | Additional metadata related to the event (if any). |
data.createdAt | string | ISO 8601 formatted date and time when the data was created. |
data.updatedAt | string | ISO 8601 formatted date and time when the data was last updated. |
layer1:crypto:consolidation:status-change
The webhook notification sends a JSON object containing details about the event. Here is an example payload:
{
"event": "layer1:digital:consolidation:status-change",
"timestamp": "2024-05-09T06:11:13.976035981Z",
"data": {
"id": "018f5bfa2e9a74edbcbb60fccbe7e842a4e464fb30554fe2a5cb4ed39a14408969",
"address": {
"id": "a4e464fb-3055-4fe2-a5cb-4ed39a144089",
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"assetPoolId": "b85cdc60-29da-4b2a-b28c-248e38cef764",
"network": "ETHEREUM",
"keyPairId": "59d0e545-2985-46c2-a834-7ab5199abbd4",
"reference": "REF-127558124LT181Y1I"
},
"reference": "consolidation-018f5bf8-f9c3-77bb-abc7-0b0597001ba1",
"status": "CREATED",
"sources": [
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "0.00050889650541582",
"asset": "ETH"
},
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "100.00",
"asset": "USDT"
}
],
"destinations": [
{
"address": "0xd399fe8c3914c9dc9f218c912c264d616e32a5ab",
"amount": "100.00",
"asset": "USDT"
}
],
"type": "CONSOLIDATION",
"asset": "USDT",
"amount": "100.00",
"createdAt": "2024-05-09T06:11:13.690Z",
"updatedAt": "2024-05-09T06:11:13.958481Z"
}
}{
"event": "layer1:digital:consolidation:status-change",
"timestamp": "2024-05-09T06:11:14.208226824Z",
"data": {
"id": "018f5bfa2e9a74edbcbb60fccbe7e842a4e464fb30554fe2a5cb4ed39a14408969",
"address": {
"id": "a4e464fb-3055-4fe2-a5cb-4ed39a144089",
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"assetPoolId": "b85cdc60-29da-4b2a-b28c-248e38cef764",
"network": "ETHEREUM",
"keyPairId": "59d0e545-2985-46c2-a834-7ab5199abbd4",
"reference": "REF-127558124LT181Y1I"
},
"reference": "consolidation-018f5bf8-f9c3-77bb-abc7-0b0597001ba1",
"status": "SIGNED",
"sources": [
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "0.00050889650541582",
"asset": "ETH"
},
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "100.00",
"asset": "USDT"
}
],
"destinations": [
{
"address": "0xd399fe8c3914c9dc9f218c912c264d616e32a5ab",
"amount": "100.00",
"asset": "USDT"
}
],
"type": "CONSOLIDATION",
"asset": "USDT",
"amount": "100.00",
"createdAt": "2024-05-09T06:11:13.690Z",
"updatedAt": "2024-05-09T06:11:14.188735Z"
}
}{
"event": "layer1:digital:consolidation:status-change",
"timestamp": "2024-05-09T06:11:14.747080547Z",
"data": {
"id": "018f5bfa2e9a74edbcbb60fccbe7e842a4e464fb30554fe2a5cb4ed39a14408969",
"address": {
"id": "a4e464fb-3055-4fe2-a5cb-4ed39a144089",
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"assetPoolId": "b85cdc60-29da-4b2a-b28c-248e38cef764",
"network": "ETHEREUM",
"keyPairId": "59d0e545-2985-46c2-a834-7ab5199abbd4",
"reference": "REF-127558124LT181Y1I"
},
"reference": "consolidation-018f5bf8-f9c3-77bb-abc7-0b0597001ba1",
"status": "DETECTED",
"sources": [
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "100.00"
}
],
"destinations": [
{
"address": "0xd399fe8c3914c9dc9f218c912c264d616e32a5ab",
"amount": "100.00"
}
],
"type": "CONSOLIDATION",
"asset": "USDT",
"amount": "100.00",
"hash": "0x74b832f44c3405846bd9a881feca9f9903bf78cca42d5706bc1cec6bc7871685",
"createdAt": "2024-05-09T06:11:13.690Z",
"updatedAt": "2024-05-09T06:11:14.726244Z"
}
}{
"event": "layer1:digital:consolidation:status-change",
"timestamp": "2024-05-09T06:11:29.376821677Z",
"data": {
"id": "018f5bfa2e9a74edbcbb60fccbe7e842a4e464fb30554fe2a5cb4ed39a14408969",
"address": {
"id": "a4e464fb-3055-4fe2-a5cb-4ed39a144089",
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"assetPoolId": "b85cdc60-29da-4b2a-b28c-248e38cef764",
"network": "ETHEREUM",
"keyPairId": "59d0e545-2985-46c2-a834-7ab5199abbd4",
"reference": "REF-127558124LT181Y1I"
},
"reference": "consolidation-018f5bf8-f9c3-77bb-abc7-0b0597001ba1",
"status": "UNCONFIRMED",
"sources": [
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "0.00023986962523329",
"asset": "ETH"
},
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "100.00",
"asset": "USDT"
}
],
"destinations": [
{
"address": "0xd399fe8c3914c9dc9f218c912c264d616e32a5ab",
"amount": "100.00",
"asset": "USDT"
}
],
"type": "CONSOLIDATION",
"asset": "USDT",
"amount": "100.00",
"hash": "0x74b832f44c3405846bd9a881feca9f9903bf78cca42d5706bc1cec6bc7871685",
"networkDetail": {
"block": {
"number": 5865626,
"timestamp": "2024-05-09T06:11:24Z"
},
"fee": {
"amount": "0.00023986962523329",
"asset": "ETH"
}
},
"createdAt": "2024-05-09T06:11:13.690Z",
"updatedAt": "2024-05-09T06:11:29.352098Z"
}
}{
"event": "layer1:digital:consolidation:status-change",
"timestamp": "2024-05-09T06:12:29.567534241Z",
"data": {
"id": "018f5bfa2e9a74edbcbb60fccbe7e842a4e464fb30554fe2a5cb4ed39a14408969",
"address": {
"id": "a4e464fb-3055-4fe2-a5cb-4ed39a144089",
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"assetPoolId": "b85cdc60-29da-4b2a-b28c-248e38cef764",
"network": "ETHEREUM",
"keyPairId": "59d0e545-2985-46c2-a834-7ab5199abbd4",
"reference": "REF-127558124LT181Y1I"
},
"reference": "consolidation-018f5bf8-f9c3-77bb-abc7-0b0597001ba1",
"status": "CONFIRMED",
"sources": [
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "100.00",
"asset": "USDT"
},
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "0.00023986962523329",
"asset": "ETH"
}
],
"destinations": [
{
"address": "0xd399fe8c3914c9dc9f218c912c264d616e32a5ab",
"amount": "100.00",
"asset": "USDT"
}
],
"type": "CONSOLIDATION",
"asset": "USDT",
"amount": "100.00",
"hash": "0x74b832f44c3405846bd9a881feca9f9903bf78cca42d5706bc1cec6bc7871685",
"networkDetail": {
"block": {
"number": 5865626,
"timestamp": "2024-05-09T06:11:24Z"
},
"fee": {
"amount": "0.00023986962523329",
"asset": "ETH"
}
},
"createdAt": "2024-05-09T06:11:13.690Z",
"updatedAt": "2024-05-09T06:12:29.545914Z"
}
}{
"event": "layer1:digital:consolidation:status-change",
"timestamp": "2024-05-09T06:12:29.702705023Z",
"data": {
"id": "018f5bfa2e9a74edbcbb60fccbe7e842a4e464fb30554fe2a5cb4ed39a14408969",
"address": {
"id": "a4e464fb-3055-4fe2-a5cb-4ed39a144089",
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"assetPoolId": "b85cdc60-29da-4b2a-b28c-248e38cef764",
"network": "ETHEREUM",
"keyPairId": "59d0e545-2985-46c2-a834-7ab5199abbd4",
"reference": "REF-127558124LT181Y1I"
},
"reference": "consolidation-018f5bf8-f9c3-77bb-abc7-0b0597001ba1",
"status": "SUCCESS",
"sources": [
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "100.00",
"asset": "USDT"
},
{
"address": "0x1bade4a7ab3f43ef98ee90045d72f70031904c84",
"amount": "0.00023986962523329",
"asset": "ETH"
}
],
"destinations": [
{
"address": "0xd399fe8c3914c9dc9f218c912c264d616e32a5ab",
"amount": "100.00",
"asset": "USDT"
}
],
"type": "CONSOLIDATION",
"asset": "USDT",
"amount": "100.00",
"hash": "0x74b832f44c3405846bd9a881feca9f9903bf78cca42d5706bc1cec6bc7871685",
"networkDetail": {
"block": {
"number": 5865626,
"timestamp": "2024-05-09T06:11:24Z"
},
"fee": {
"amount": "0.00023986962523329",
"asset": "ETH"
}
},
"createdAt": "2024-05-09T06:11:13.690Z",
"updatedAt": "2024-05-09T06:12:29.680325Z"
}
}Below is a detailed explanation of each field in the webhook payload:
| Field | Type | Description |
|---|---|---|
event | string | Identifies the type of event, e.g., "layer1:digital:consolidation:status-change" |
timestamp | string | ISO 8601 formatted date and time when the event was generated. |
data | object | Contains detailed information about the event. |
data.id | string | Unique identifier for the event. |
data.address | object | Details of the address involved in the consolidation. |
data.address.id | string | Unique identifier for the address object. |
data.address.address | string | The cryptocurrency address involved. |
data.address.assetPoolId | string | Identifier of the asset pool this address belongs to, in GUID format. |
data.address.network | string | The network for the cryptocurrency address. |
data.address.keyPairId | string | Identifier for the key pair associated with the address, in GUID format. |
data.address.reference | string | A reference identifier linked to the address. |
data.reference | string | A general reference identifier for the consolidation event. |
data.status | string | Current status of the consolidation [CREATED, SIGNED, DETECTED, UNCONFIRMED, CONFIRMED, SUCCESS]. |
data.sources[] | array | Array of source addresses and amounts involved in the consolidation. |
data.sources[].address | string | The source address involved in the transaction. |
data.sources[].amount | string | The amount of the asset being transferred from the source address. |
data.sources[].asset | string | Type of asset being transferred. |
data.destinations[] | array | Array of destination addresses and amounts being transferred. |
data.destinations[].address | string | The destination address involved in the transaction. |
data.destinations[].amount | string | The amount of the asset being transferred to the destination address. |
data.destinations[].asset | string | Type of asset being transferred. |
data.type | string | Type of transaction. |
data.asset | string | Type of asset involved in the transaction. |
data.amount | string | Total amount of the asset being consolidated. |
data.hash | string | Transaction hash. |
data.networkDetail | object | Additional details about the network state at the time of the transaction. |
data.networkDetail.block | object | Block information relevant to the transaction. |
data.networkDetail.block.number | string | Block number associated with the transaction. |
data.networkDetail.block.timestamp | string | Timestamp of the block. |
data.networkDetail.fee | object | Fee information related to the transaction. |
data.networkDetail.fee.amount | string | Amount of the fee charged. |
data.networkDetail.fee.asset | string | Asset type of the fee. |
data.createdAt | string | ISO 8601 formatted date and time when the data was created. |
data.updatedAt | string | ISO 8601 formatted date and time when the data was last updated. |
layer1:trade:conversion:created
The webhook notification sends a JSON object containing details about the event. Here is an example payload:
{
"event": "layer1:trade:conversion:created",
"timestamp": null,
"data": {
"id": "65a726c7-e56f-4bf0-b65e-7225d8abd9ee",
"reference": "13963121-6626-4694-8fb8-9557db7b5a04",
"status": "PENDING",
"from": {
"asset": "EUR",
"amount": 100
},
"to": {
"asset": "LTC",
"amount": 1.386770212175842462
},
"orders": null,
"router": "VWAP",
"executor": "MAKER",
"movements": null,
"createdAt": null
}
}Below is a detailed explanation of each field in the webhook payload:
| Field | Type | Description |
|---|---|---|
event | string | Identifies the type of event, e.g., "layer1:trade:conversion:created". |
timestamp | null | The time when the event was generated, can be null. |
data | object | Contains detailed information about the event. |
data.id | string | Unique identifier for the conversion event, in GUID format. |
data.reference | string | A reference identifier linked to the conversion, in GUID format. |
data.status | string | Current status of the conversion a the time of creation. |
data.from | object | Details about the currency from which is converted. |
data.from.asset | string | Type of asset being converted from. |
data.from.amount | number | Amount of the asset being converted. |
data.to | object | Details about the currency to which is converted. |
data.to.asset | string | Type of asset being converted to. |
data.to.amount | number | Amount of the asset after conversion. |
data.orders | null | Details of any orders involved in the conversion, can be null. |
data.router | string | Routing mechanism used for the conversion [VWAP]. |
data.executor | string | Execution type for the conversion [MAKER]. |
data.movements | null | Any movements related to the conversion, can be null. |
data.createdAt | null | The time when the conversion was created, can be null. |
layer1:trade:conversion:state-changed
The webhook notification sends a JSON object containing details about the event. Here is the example payloads:
{
"event": "layer1:trade:conversion:state-changed",
"timestamp": "2024-05-01T14:49:43.151138Z",
"data": {
"id": "65a726c7-e56f-4bf0-b65e-7225d8abd9ee",
"reference": "13963121-6626-4694-8fb8-9557db7b5a04",
"status": "PLACED",
"from": {
"asset": "EUR",
"amount": 100
},
"to": {
"asset": "LTC",
"amount": 1.386770212175842462
},
"orders": [
{
"symbol": "LTC-EUR",
"side": "BUY",
"targetPrice": 72.11,
"targetQuantity": 1.386770212175842462,
"venue": "kraken",
"output": 0,
"id": "234098b4-f55b-4ef6-9ea3-1d28010d8476",
"venueOrderId": "cd5009ad-ecd4-438a-813c-7608c85833d7",
"status": "PLACED",
"actualPrice": 0,
"actualQuantity": 0,
"createdAt": "2024-05-01T14:49:43.157286Z"
}
],
"router": "VWAP",
"executor": "MAKER",
"movements": [],
"createdAt": "2024-05-01T14:49:43.151138Z"
}
}{
"event": "layer1:trade:conversion:state-changed",
"timestamp": "2024-05-01T14:49:43.151138Z",
"data": {
"id": "65a726c7-e56f-4bf0-b65e-7225d8abd9ee",
"reference": "13963121-6626-4694-8fb8-9557db7b5a04",
"status": "COMPLETED",
"from": {
"asset": "EUR",
"amount": 100
},
"to": {
"asset": "LTC",
"amount": 1.386770212175842462
},
"orders": [
{
"symbol": "LTC-EUR",
"side": "BUY",
"targetPrice": 72.11,
"targetQuantity": 1.386770212175842462,
"venue": "kraken",
"output": 0,
"id": "234098b4-f55b-4ef6-9ea3-1d28010d8476",
"venueOrderId": "cd5009ad-ecd4-438a-813c-7608c85833d7",
"status": "CANCELLED",
"actualPrice": 72.050216507121990198,
"actualQuantity": 0.21356492612732545,
"createdAt": "2024-05-01T14:49:43.157286Z"
},
{
"symbol": "LTC-EUR",
"side": "BUY",
"targetPrice": 72.11,
"targetQuantity": 1.173382344115915787,
"venue": "kraken",
"output": 0,
"id": "a1c86126-9c56-407a-902c-a89a15d198f1",
"venueOrderId": "5e893e50-9260-435a-ac5c-e7430dbf34e5",
"status": "COMPLETED",
"actualPrice": 72.11,
"actualQuantity": 1.17338234,
"createdAt": "2024-05-01T14:50:44.788691Z"
}
],
"router": "VWAP",
"executor": "MAKER",
"movements": [
{
"asset": "LTC",
"amount": 1.38694726612732545
},
{
"asset": "EUR",
"amount": -99.9999997032013125489753309548559391
}
],
"createdAt": "2024-05-01T14:49:43.151138Z"
}
}Below is a detailed explanation of each field in the webhook payload:
| Field | Type | Description |
|---|---|---|
event | string | Identifies the type of event, e.g., "layer1:trade:conversion:state-changed". |
timestamp | string | ISO 8601 formatted date and time when the event was generated. |
data.id | string | Unique identifier for the conversion event, in GUID format. |
data.reference | string | A reference identifier linked to the conversion, in GUID format. |
data.status | string | Current status of the conversion [PLACED, COMPLETE]. |
data.from.asset | string | Type of asset being converted from. |
data.from.amount | float | Amount of the asset being converted. |
data.to.asset | string | Type of asset being converted to. |
data.to.amount | float | Amount of the asset received after conversion. |
data.orders[] | array | Array containing details of orders involved in the conversion. |
data.orders[].symbol | string | Trading pair symbol. |
data.orders[].side | string | Transaction side. |
data.orders[].targetPrice | float | Target price for the order. |
data.orders[].targetQuantity | float | Target quantity for the order. |
data.orders[].venue | string | Venue where the order was placed. |
data.orders[].output | int | Output index of the order (for complex trades involving multiple orders). |
data.orders[].id | string | Unique identifier for the order, in GUID format. |
data.orders[].venueOrderId | string | Unique identifier provided by the trading venue for the order, in GUID format. |
data.orders[].status | string | Current status of the order [PLACED, COMPLETED]. |
data.orders[].actualPrice | float | Actual price at which the order was executed. |
data.orders[].actualQuantity | float | Actual quantity of the asset received from the order. |
data.orders[].createdAt | string | ISO 8601 formatted date and time when the order was created. |
data.router | string | Routing mechanism used for the conversion [VWAP]. |
data.executor | string | Type of execution used for processing the conversion [MAKER]. |
data.movements[] | array | Array detailing any asset movements and amounts related to the conversion. |
data.createdAt | string | ISO 8601 formatted date and time when the conversion was created. |
layer1:digital:balance:updated
The webhook notification sends a JSON object containing details about the event. Here is the example payloads:
{
"event": "layer1:digital:balance:updated",
"timestamp": "2024-06-05T20:40:16.941138099Z",
"data": {
"reference": "First Eth Address",
"address": "0xc4b21fb39aaf5fc07d3cd4420bf3ee74a61642e9",
"asset": "ETH",
"funds": [
{
"type": "AVAILABLE",
"balance": "0.00",
"delta": "0.00"
},
{
"type": "BLOCKCHAIN",
"balance": "0.20",
"delta": "0.20"
},
{
"type": "RESERVED",
"balance": "0.20",
"delta": "0.20"
}
]
}
}Below is a detailed explanation of each field in the webhook payload:
| Field | Description |
|---|---|
| event | The type of event that triggered the webhook. |
| timestamp | The time when the event occurred in ISO 8601 format. |
| data | A nested object containing details of the balance update. |
| data.reference | A unique reference for the crypto address. |
| data.address | The crypto address involved in the balance update. |
| data.asset | The type of cryptocurrency asset. |
| data.funds | An array containing details of the fund balances. |
| data.funds.type | The type of fund balance [AVAILABLE, BLOCKCHAIN, RESERVED]. |
| data.funds.balance | The current balance of the fund type. |
| data.funds.delta | The change in balance for the fund type. |
layer1:approval:request:status-changed
The webhook informs about all the completed requests: approved, rejected, and expired. It is not updated if a request is created or pending.
{
"event": "layer1:approval:request:status-changed",
"eventId": "01990e61-728d-7451-a20a-2bc92bd0eeef",
"timestamp": "2025-09-03T07:01:31.405719073Z",
"data": {
"votes": [
{
"note": "",
"vote": "APPROVED",
"voter": "[email protected]"
}
],
"status": "APPROVED",
"context": {
"namespace": "contact_trusted_address",
"newSettings": "{ \"address\": { \"defaultApprovalsCount\": 0 } }",
"oldSettings": "{ \"address\": { \"defaultApprovalsCount\": 1 } }"
},
"createdAt": "2025-09-03T07:00:19.167377Z",
"expiresAt": "2025-09-10T07:00:19.167377Z",
"requester": "service-account-master-id",
"updatedAt": "2025-09-03T07:01:31.288558Z",
"description": "Approval settings update for contact_trusted_address",
"operationId": "01990e60-585f-7e64-8e51-7fdf3360f18f",
"requirement": {
"policyName": "approval_settings",
"resolvedRequirement": {
"type": "any",
"requirements": [
{
"roleId": "layer1:role:approval-settings:operator",
"requiredApprovals": 1
}
]
}
}
}
}{
"event": "layer1:approval:request:status-changed",
"eventId": "01990dff-4b2a-785b-bc62-0ae7961001fc",
"timestamp": "2025-09-03T05:14:18.794409381Z",
"data": {
"votes": [
{
"note": "",
"vote": "APPROVED",
"voter": "[email protected]"
}
],
"status": "APPROVED",
"context": {
"asset": "eur",
"amount": 10,
"idType": "BVNK_PARTNER_ACCOUNT",
"idValue": "a:24111355910083:eKiIYeI:1",
"sources": [
{
"asset": "eur",
"amount": 10,
"managedBalanceId": "bvnk_kraken_eur"
}
],
"usdAmount": 11.7066,
"targetBalance": 311300.08,
"managedBalanceId": "bvnk_lhv-malta_eur",
"balanceWhenRequestingApproval": 311290.08
},
"createdAt": "2025-09-03T05:13:51.127317Z",
"expiresAt": "2025-09-03T05:21:51.127317Z",
"requester": "service-account-treasury-cli",
"updatedAt": "2025-09-03T05:14:18.732090Z",
"description": "[Transfer of 10.00 eur from bvnk_kraken_eur to bvnk_lhv-malta_eur]",
"operationId": "01990dfe-de81-7204-bfa4-d693b71547c9",
"requirement": {
"policyName": "automated_liquidity_management",
"resolvedRequirement": {
"type": "any",
"requirements": [
{
"roleId": "layer1:role:treasury:operator-limited",
"requiredApprovals": 1
},
{
"roleId": "layer1:role:treasury:admin",
"requiredApprovals": 1
},
{
"roleId": "layer1:role:crypto:liquidity:operator",
"requiredApprovals": 1
}
]
}
}
}
}layer1:approval:request:vote-required
The webhook is pushed only if the request waits for a user's vote. It won't be received if an approval request is auto-approved or auto-rejected.
{
"event": "layer1:approval:request:vote-required",
"eventId": "01990e60-cf27-785b-a4e3-13d815621d5a",
"timestamp": "2025-09-03T07:00:49.575300517Z",
"data": {
"votes": [],
"status": "PENDING",
"context": {
"namespace": "approval_settings",
"newSettings": "{ \"defaultApprovalsCount\": 0 }",
"oldSettings": "{ \"defaultApprovalsCount\": 1 }"
},
"createdAt": "2025-09-03T07:00:49.498950Z",
"expiresAt": "2025-09-10T07:00:49.498950Z",
"requester": "service-account-master-id",
"updatedAt": "2025-09-03T07:00:49.561050Z",
"description": "Approval settings update for approval_settings",
"operationId": "01990e60-ceda-7b21-9592-d7a439f63916",
"requirement": {
"policyName": "approval_settings",
"resolvedRequirement": {
"type": "any",
"requirements": [
{
"roleId": "layer1:role:approval-settings:operator",
"requiredApprovals": 1
}
]
}
}
}
}{
"event": "layer1:approval:request:vote-required",
"eventId": "01990dfe-dfad-7ba8-8b3d-e4b4f7791f21",
"timestamp": "2025-09-03T05:13:51.277417301Z",
"data": {
"votes": [],
"status": "PENDING",
"context": {
"asset": "eur",
"amount": 10,
"idType": "BVNK_PARTNER_ACCOUNT",
"idValue": "a:24111355910083:eKiIYeI:1",
"sources": [
{
"asset": "eur",
"amount": 10,
"managedBalanceId": "bvnk_kraken_eur"
}
],
"usdAmount": 11.7066,
"targetBalance": 311300.08,
"managedBalanceId": "bvnk_lhv-malta_eur",
"balanceWhenRequestingApproval": 311290.08
},
"createdAt": "2025-09-03T05:13:51.127317Z",
"expiresAt": "2025-09-03T05:21:51.127317Z",
"requester": "service-account-treasury-cli",
"updatedAt": "2025-09-03T05:13:51.246611Z",
"description": "[Transfer of 10.00 eur from bvnk_kraken_eur to bvnk_lhv-malta_eur]",
"operationId": "01990dfe-de81-7204-bfa4-d693b71547c9",
"requirement": {
"policyName": "automated_liquidity_management",
"resolvedRequirement": {
"type": "any",
"requirements": [
{
"roleId": "layer1:role:treasury:operator-limited",
"requiredApprovals": 1
},
{
"roleId": "layer1:role:treasury:admin",
"requiredApprovals": 1
},
{
"roleId": "layer1:role:crypto:liquidity:operator",
"requiredApprovals": 1
}
]
}
}
}
}layer1:audit:api
This webhook is sent for necessary, predefined API calls configured on the API gateway. It serves as a common audit event that triggers for every authenticated action performed on our APIs, covering platform operations such as creating transactions, creating wallets, and similar actions. An authenticated party executes all actions captured by this webhook.
{
"event": "layer1:audit:api",
"eventId": "0196f305-e4a5-7b8d-8b88-019ff473057e",
"timestamp": "2025-05-21T13:26:11.877306371Z",
"data": {
"authInfo": {
"authScheme": "jwt",
"userId": "d1f25012-aa63-40f8-b073-b85f6b3c286d",
"username": "[email protected]",
"impersonatorId": "1720a571-e2d0-439e-9aee-008dd3103e8c", // if present
"impersonatorUsername": "[email protected]", // if present
"clientId": "bvnk-customer-portal",
"levelOfAuthentication": 2, // (acr)
"issuedAt": "2025-05-21T13:26:11.877306371Z",
"expiresAt": "2025-05-21T13:31:11.877306371Z",
"tokenId": "6124e7c8-648d-45fc-973d-c9a1fa5c305a",
"sessionId": "2c82a9ab-55eb-42ad-9141-08e4c0c28a35"
},
"method": "POST",
"path": "/digital/v1/transaction-requests",
"digest": "Db1VDDIemUCnsR3wxhc2onLHgRqpO0iRuY",
"requestBodySize": 432,
"responseBodySize": 0,
"httpStatus": 201,
"clientIp": "52.213.39.97",
"clientPort": 53821,
"receivedAt": "2025-05-21T13:26:11.877306371Z",
"upstreamDurationMiliseconds": 123,
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...",
"traceId": "1720a571-e2d0-439e-9aee-008dd3103e8c"
}
}Field | Type | Description |
|---|---|---|
| string | Type of the event being logged. Here it is: |
| string($uuid) | Unique identifier for this event. |
| string($date-time) | Time when the event occurred. |
| object | The data object containing request and response information. |
| object | Information about the authentication of the request. Can be either JWT or Hawk authentication. |
| string | Authentication scheme used:
|
| string($uuid) | ID of the authenticated user (JWT only). |
| string($email) | Username of the authenticated user (JWT only). |
| string($uuid) | ID of the impersonating user, if present (JWT only). |
| string($email) | Username of the impersonating user, if present (JWT only). |
| string | OAuth2 client ID used for authentication (JWT only). |
| integer | ACR (Authentication Context Class Reference) value (JWT only). |
| string($date-time) | Time at which the token was issued (JWT only). |
| string($date-time) | Expiry time of the token (JWT only). |
| string($uuid) | Unique identifier for the token (JWT only). |
| string($uuid) | Identifier for the user's session (JWT only). |
| string | The Hawk ID used for authentication (user or client key ID) (Hawk only). |
| string | UNIX timestamp as a string (Hawk only). |
| string | HTTP method used for the request. |
| string | API path that was accessed. |
| string | Digest hash of the request body. |
| integer | Size of the HTTP request body in bytes. |
| integer | Size of the HTTP response body in bytes. |
| integer | HTTP status code of the response. Not present in case of timeouts (nullable). |
| string($ipv4) | IP address of the client making the request. |
| integer | Port number of the client connection. |
| string($date-time) | Time the request was received. |
| integer | Time spent on the upstream call in milliseconds. |
| string | User agent string from the client making the request. |
| string($uuid) | Trace identifier for distributed tracing. |
layer1:audit:auth:login
This webhook captures user and client login events recorded by Keycloak. To enhance the audit trail with comprehensive login information, Layer1 leverages Keycloak as an authentication provider, which exposes its own set of events. A custom event listener implemented within Keycloak wraps these events into the layer1:audit:auth:login webhook format, providing a unified audit log for all authentication activities.
{
"event": "layer1:audit:auth:login",
"eventId": "0196f305-e4a5-7b8d-8b88-019ff473057e",
"timestamp": "2025-05-21T13:26:11.877306371Z",
"data": {
"type": "LOGIN",
"clientId": "bvnk-customer-portal",
"userId": "ef91d6a3-af07-4666-9cbb-8cdb9028f3f7",
"sessionId": "7a7cfd90-c459-4b6c-85db-75f01ae0f963",
"ipAddress": "62.176.70.8",
"details": {
"identity_provider": "Okta",
"identity_provider_identity": "[email protected]",
"username": "[email protected]"
}
}
}{
"event": "layer1:audit:auth:login",
"eventId": "0196f305-e4a5-7b8d-8b88-019ff473057e",
"timestamp": "2025-05-21T13:26:11.877306371Z",
"data": {
"type": "LOGIN",
"clientId": "bvnk-customer-portal",
"userId": "9cbd7860-0334-48ba-9a8f-535f70711554",
"sessionId": "fb0bbcec-5daa-49eb-a4c6-2246868bd987",
"ipAddress": "62.176.70.8",
"details": {
"credential_type": "webauthn-passwordless",
"web_authn_authenticator_user_verification_checked": "false",
"auth_method": "openid-connect",
"redirect_uri": "https://app.staging.layer1.com/",
"username": "[email protected]"
}
}
}{
"event": "layer1:audit:auth:login",
"eventId": "0196f305-e4a5-7b8d-8b88-019ff473057e",
"timestamp": "2025-05-21T13:26:11.877306371Z",
"data": {
"type": "CODE_TO_TOKEN",
"clientId": "bvnk-customer-portal",
"userId": "ef91d6a3-af07-4666-9cbb-8cdb9028f3f7",
"sessionId": "7a7cfd90-c459-4b6c-85db-75f01ae0f963",
"ipAddress": "62.176.70.8",
"details": {
"token_id": "3f3d1818-9511-48a4-a2f0-74727252b396",
"grant_type": "authorization_code",
"refresh_token_type": "Refresh",
"scope": "openid venue-deposit-addresses:edit transaction-claims:edit payment-admin:edit payment-admin:view configuration-hook:view approvals:edit account:view books:view staking-transactions:edit asset-pools:view asset-pools:admin networks:view fee:configuration:edit channel-payments:view transactions:edit quote:edit exports:view webhook:edit webhook:view payment:view networks:edit fee:edit book-entries:view layer1:scope:roles exchange-rates:view venue-deposit-addresses:view fee:configuration:view configuration-trade:edit conversions:view clients:view asset:edit account:edit configuration-trade:view channels:edit book-entries:edit venue-transfer:view hook-destinations:view trade-settings:edit addresses:admin treasury:admin approval-settings:view asset-pools:consolidation identity-user:edit superset:edit failing-configurations:view failing-configurations:edit configuration-digital:view ledger:admin fee-estimate:edit exports:edit books:edit hook-destinations:edit screenings:edit tenants:view addresses:edit venue-transfer:edit keypairs:view addresses:view report:view hook-events:view quote:view profile venue-balances:view email transactions:view channels:view trade-settings:view configuration-digital:edit identity-user:view conversions:edit screenings:view configuration-hook:edit wallet:view payment:edit asset-pools:support hook:admin asset-pools:edit wallet:edit keypairs:edit clients:edit",
"client_auth_method": "client-secret"
}
}
}{
"event": "layer1:audit:auth:login",
"eventId": "0196f305-e4a5-7b8d-8b88-019ff473057e",
"timestamp": "2025-05-21T13:26:11.877306371Z",
"data": {
"type": "LOGIN_ERROR",
"clientId": "bvnk-customer-portal",
"userId": "9cbd7860-0334-48ba-9a8f-535f70711554",
"ipAddress": "62.176.70.8",
"error": "invalid_user_credentials",
"details": {
"auth_method": "openid-connect",
"auth_type": "code",
"redirect_uri": "https://app.staging.layer1.com/",
"username": "[email protected]"
}
}
}{
"event": "layer1:audit:auth:login",
"eventId": "0196f305-e4a5-7b8d-8b88-019ff473057e",
"timestamp": "2025-05-21T13:26:11.877306371Z",
"data": {
"type": "LOGOUT",
"clientId": "bvnk-customer-portal",
"userId": "ef91d6a3-af07-4666-9cbb-8cdb9028f3f7",
"sessionId": "7a7cfd90-c459-4b6c-85db-75f01ae0f963",
"ipAddress": "62.176.70.8",
"details": {
"redirect_uri": "https://app.staging.layer1.com"
}
}
}{
"event": "layer1:audit:auth:login",
"eventId": "0196f305-e4a5-7b8d-8b88-019ff473057e",
"timestamp": "2025-05-21T13:26:11.877306371Z",
"data": {
"type": "CLIENT_LOGIN",
"clientId": "65ef551b-eccc-4c78-9835-c3154a8dbd89",
"userId": "5196682d-d63f-4377-ac21-51474503901d",
"sessionId": "e009d1b1-5b6e-4350-a137-ae9868d6510d",
"ipAddress": "52.213.39.97",
"details": {
"token_id": "fd11f853-5c2e-415f-a586-f36561212640",
"grant_type": "client_credentials",
"scope": "venue-deposit-addresses:edit transaction-claims:edit payment-admin:edit payment-admin:view configuration-hook:view account:view asset-pools:admin staking-transactions:edit asset-pools:view networks:view fee:configuration:edit transactions:edit channel-payments:view exports:view webhook:edit payment:view webhook:view networks:edit fee:edit channels-admin:view layer1:scope:roles exchange-rates:view venue-deposit-addresses:view fee:configuration:view configuration-trade:edit conversions:view asset:edit account:edit clients:view configuration-trade:view channels:edit venue-transfer:view trade-settings:edit hook-destinations:view addresses:admin treasury:admin asset-pools:consolidation identity-user:edit failing-configurations:view failing-configurations:edit configuration-digital:view address ledger:admin fee-estimate:edit exports:edit hook-destinations:edit screenings:edit tenants:view addresses:edit tenants:edit keypairs:view offline_access venue-transfer:edit addresses:view hook-events:view profile venue-balances:view phone email transactions:view channels:view trade-settings:view channels-admin:edit configuration-digital:edit identity-user:view conversions:edit configuration-hook:edit screenings:view wallet:view payment:edit asset-pools:support hook:admin asset-pools:edit wallet:edit keypairs:edit clients:edit",
"client_auth_method": "client-secret",
"username": "service-account-65ef551b-eccc-4c78-9835-c3154a8dbd89"
}
}
}{
"event": "layer1:audit:auth:login",
"eventId": "0196f305-e4a5-7b8d-8b88-019ff473057e",
"timestamp": "2025-05-21T13:26:11.877306371Z",
"data": {
"type": "CLIENT_LOGIN_ERROR",
"clientId": "01922451-20d1-71ba-a328-95811dc371ae",
"ipAddress": "62.176.70.8",
"error": "invalid_client_credentials",
"details": {
"grant_type": "client_credentials"
}
}
}Field | Type | Description |
|---|---|---|
| string | Type of the event being logged. Here it is: |
| string($uuid) | Unique identifier for this event. |
| string($date-time) | Time when the event occurred. |
| object | The data object containing authentication event information. |
| string | Type of authentication event. Possible values:
|
| string | OAuth2 client ID used for authentication. |
| string($uuid) | ID of the authenticated user (nullable, not present in error cases). |
| string($uuid) | Identifier for the user's session (nullable, not present in error cases). |
| string($ipv4) | IP address of the client making the request. |
| string | Error code for failed authentication attempts (only present in error cases). |
| object | Additional details specific to the authentication method and event type. |
| string | Identity provider used for authentication (e.g., "Okta"). |
| string | Identity from the identity provider. |
| string | Username of the authenticated user. |
| string | Type of credential used for authentication. |
| string | Whether WebAuthn user verification was checked. |
| string | Authentication method used. |
| string | Redirect URI used in the authentication flow. |
| string($uuid) | Unique identifier for the token. |
| string | OAuth2 grant type used (e.g., "authorization_code", "client_credentials"). |
| string | Type of refresh token issued. |
| string | OAuth2 scopes granted to the token. |
| string | Client authentication method used. |
| string | Type of authentication flow. |