Skip to main content
Layer1

Webhooks

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 payload

Do 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);
}
}

Webhook details​

For the detailed description of webhooks and their fields, see the Layer1 webhook reference.

Webhooks​

layer1:crypto:address:created​

The webhook notification sends a JSON object containing details about the event. Here is an example payload:

Address Created
{
"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:

FieldTypeDescription
eventstringIdentifies the type of event. Example: "layer1:crypto:address:created"
timestampstringISO 8601 formatted date and time when the event was generated.
dataobjectContains detailed information about the event.
data.idstringUnique identifier for the event, in GUID format.
data.addressstringThe cryptocurrency address that was created.
data.networkstringThe network for the cryptocurrency address.
data.keyPairIdstringIdentifier for the key pair associated with the address, in GUID format.
data.referencestringA reference identifier linked to the creation of this address, in GUID format.
data.assetPoolIdstringIdentifier 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",
},
};

Below is a detailed explanation of each field in the webhook payload:

FieldTypeDescription
eventstringIdentifies the type of event. Example: "layer1:crypto:deposit:status-change"
timestampstringISO 8601 formatted date and time when the event was generated.
dataobjectContains detailed information about the event.
data.idstringUnique identifier for the event.
data.addressobjectDetailed information about the address involved in the deposit.
data.address.idstringUnique identifier for the address object, in GUID format.
data.address.addressstringThe cryptocurrency address involved.
data.address.assetPoolIdstringIdentifier of the asset pool this address belongs to, in GUID format.
data.address.networkstringThe network for the cryptocurrency address
data.address.keyPairIdstringIdentifier for the key pair associated with the address, in GUID format.
data.address.referencestringA reference identifier linked to the creation of this address.
data.referencenull/stringA general reference identifier, can be null.
data.statusstringCurrent status of the deposit [DETECTED, UNCONFIRMED, CONFIRMED, SCREENING_REQUESTED, SUCCESS].
data.sources[]arrayArray of source addresses and amounts involved in the transaction.
data.destinations[]arrayArray of destination addresses and amounts involved in the transaction.
data.typestringType of transaction.
data.assetstringType of asset involved in the transaction.
data.amountstringAmount of the asset involved in the transaction.
data.hashstringTransaction hash.
data.networkDetailnullAdditional network-specific details, can be null.
data.metadatanullAdditional metadata related to the event, can be null.
data.createdAtstringISO 8601 formatted date and time when the data was created.
data.updatedAtstringISO 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"
}
}

Below is a detailed explanation of each field in the webhook payload:

FieldTypeDescription
eventstringIdentifies the type of event, for example, "layer1:crypto:withdrawal:status-change"
timestampstringISO 8601 formatted date and time when the event was generated.
dataobjectContains detailed information about the event.
data.idstringUnique identifier for the event.
data.addressobjectDetails of the address involved in the withdrawal.
data.address.idstringUnique identifier for the address object.
data.address.addressstringThe cryptocurrency address involved.
data.address.assetPoolIdstringIdentifier of the asset pool this address belongs to, in GUID format.
data.address.networkstringThe network for the cryptocurrency address.
data.address.keyPairIdstringIdentifier for the key pair associated with the address, in GUID format.
data.address.referencestringA reference identifier linked to the address.
data.referencestringA general reference identifier for the withdrawal.
data.statusstringCurrent status of the withdrawal [CREATED, SIGNED,UNCONFIRMED, CONFIRMED].
data.sources[]arrayArray of source addresses and amounts involved in the withdrawal.
data.destinations[]arrayArray of destination addresses and amounts being transferred.
data.typestringType of transaction.
data.assetstringType of asset involved in the transaction.
data.amountstringTotal amount of the asset being withdrawn.
data.hashstringTransaction hash.
data.networkDetailobjectAdditional details about the network state at the time of the transaction.
data.networkDetail.blockobjectBlock information relevant to the transaction.
data.networkDetail.block.numberstringBlock number associated with the transaction.
data.networkDetail.block.timestampstringTimestamp of the block.
data.networkDetail.feeobjectFee information related to the transaction.
data.networkDetail.fee.amountstringAmount of the fee charged.
data.networkDetail.fee.assetstringAsset type of the fee (for example, ETH).
data.metadatanullAdditional metadata related to the event (if any).
data.createdAtstringISO 8601 formatted date and time when the data was created.
data.updatedAtstringISO 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:crypto: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"
}
}

Below is a detailed explanation of each field in the webhook payload:

FieldTypeDescription
eventstringIdentifies the type of event, for example, "layer1:crypto:consolidation:status-change"
timestampstringISO 8601 formatted date and time when the event was generated.
dataobjectContains detailed information about the event.
data.idstringUnique identifier for the event.
data.addressobjectDetails of the address involved in the consolidation.
data.address.idstringUnique identifier for the address object.
data.address.addressstringThe cryptocurrency address involved.
data.address.assetPoolIdstringIdentifier of the asset pool this address belongs to, in GUID format.
data.address.networkstringThe network for the cryptocurrency address.
data.address.keyPairIdstringIdentifier for the key pair associated with the address, in GUID format.
data.address.referencestringA reference identifier linked to the address.
data.referencestringA general reference identifier for the consolidation event.
data.statusstringCurrent status of the consolidation [CREATED, SIGNED, DETECTED, UNCONFIRMED, CONFIRMED, SUCCESS].
data.sources[]arrayArray of source addresses and amounts involved in the consolidation.
data.sources[].addressstringThe source address involved in the transaction.
data.sources[].amountstringThe amount of the asset being transferred from the source address.
data.sources[].assetstringType of asset being transferred.
data.destinations[]arrayArray of destination addresses and amounts being transferred.
data.destinations[].addressstringThe destination address involved in the transaction.
data.destinations[].amountstringThe amount of the asset being transferred to the destination address.
data.destinations[].assetstringType of asset being transferred.
data.typestringType of transaction.
data.assetstringType of asset involved in the transaction.
data.amountstringTotal amount of the asset being consolidated.
data.hashstringTransaction hash.
data.networkDetailobjectAdditional details about the network state at the time of the transaction.
data.networkDetail.blockobjectBlock information relevant to the transaction.
data.networkDetail.block.numberstringBlock number associated with the transaction.
data.networkDetail.block.timestampstringTimestamp of the block.
data.networkDetail.feeobjectFee information related to the transaction.
data.networkDetail.fee.amountstringAmount of the fee charged.
data.networkDetail.fee.assetstringAsset type of the fee.
data.createdAtstringISO 8601 formatted date and time when the data was created.
data.updatedAtstringISO 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:

Conversion - CREATED
{
"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:

FieldTypeDescription
eventstringIdentifies the type of event, for example, "layer1:trade:conversion:created".
timestampnullThe time when the event was generated, can be null.
dataobjectContains detailed information about the event.
data.idstringUnique identifier for the conversion event, in GUID format.
data.referencestringA reference identifier linked to the conversion, in GUID format.
data.statusstringCurrent status of the conversion a the time of creation.
data.fromobjectDetails about the currency from which is converted.
data.from.assetstringType of asset being converted from.
data.from.amountnumberAmount of the asset being converted.
data.toobjectDetails about the currency to which is converted.
data.to.assetstringType of asset being converted to.
data.to.amountnumberAmount of the asset after conversion.
data.ordersnullDetails of any orders involved in the conversion, can be null.
data.routerstringRouting mechanism used for the conversion [VWAP].
data.executorstringExecution type for the conversion [MAKER].
data.movementsnullAny movements related to the conversion, can be null.
data.createdAtnullThe 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"
}
}

Below is a detailed explanation of each field in the webhook payload:

FieldTypeDescription
eventstringIdentifies the type of event, for example, "layer1:trade:conversion:state-changed".
timestampstringISO 8601 formatted date and time when the event was generated.
data.idstringUnique identifier for the conversion event, in GUID format.
data.referencestringA reference identifier linked to the conversion, in GUID format.
data.statusstringCurrent status of the conversion [PLACED, COMPLETE].
data.from.assetstringType of asset being converted from.
data.from.amountfloatAmount of the asset being converted.
data.to.assetstringType of asset being converted to.
data.to.amountfloatAmount of the asset received after conversion.
data.orders[]arrayArray containing details of orders involved in the conversion.
data.orders[].symbolstringTrading pair symbol.
data.orders[].sidestringTransaction side.
data.orders[].targetPricefloatTarget price for the order.
data.orders[].targetQuantityfloatTarget quantity for the order.
data.orders[].venuestringVenue where the order was placed.
data.orders[].outputintOutput index of the order (for complex trades involving multiple orders).
data.orders[].idstringUnique identifier for the order, in GUID format.
data.orders[].venueOrderIdstringUnique identifier provided by the trading venue for the order, in GUID format.
data.orders[].statusstringCurrent status of the order [PLACED, COMPLETED].
data.orders[].actualPricefloatActual price at which the order was executed.
data.orders[].actualQuantityfloatActual quantity of the asset received from the order.
data.orders[].createdAtstringISO 8601 formatted date and time when the order was created.
data.routerstringRouting mechanism used for the conversion [VWAP].
data.executorstringType of execution used for processing the conversion [MAKER].
data.movements[]arrayArray detailing any asset movements and amounts related to the conversion.
data.createdAtstringISO 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:

FieldDescription
eventThe type of event that triggered the webhook.
timestampThe time when the event occurred in ISO 8601 format.
dataA nested object containing details of the balance update.
data.referenceA unique reference for the crypto address.
data.addressThe crypto address involved in the balance update.
data.assetThe type of cryptocurrency asset.
data.fundsAn array containing details of the fund balances.
data.funds.typeThe type of fund balance [AVAILABLE, BLOCKCHAIN, RESERVED].
data.funds.balanceThe current balance of the fund type.
data.funds.deltaThe change in balance for the fund type.
Was this page helpful?