Skip to main content

Configure webhooks

Webhooks provide real-time, automated notifications for changes in your BVNK account.

Configure them for key events, including:

  • Pay-ins received
  • Payouts sent
  • Refunds initiated
  • Transaction status changes

This capability is essential for automating your workflows. For example, you can instantly credit a customer's wallet when a successful deposit webhook is received, eliminating the need for manual confirmation in the BVNK Portal.

For the detailed description list of webhooks, see the Webhooks API Reference.

Create webhooks

To create a webhook, do the following:

  1. Log in to the BVNK Portal.

  2. On the sidebar, click Integrations, go to the Webhooks tab, and click Add webhook.

  3. In the Add new webhook dialogue, specify the following webhook settings:

    • Description: Provide a short, meaningful description for the webhook.
    • Webhook URL to receive events: Enter the Webhook URL to which the events will be sent.
    • Events to send: Select the events to send from the list provided.

    Here, you can select events for operations related to fiat and crypto.

  4. Click Add.

The new active webhook appears in the list of webhooks where you can now manage the configuration going forward.

You're all set. You will receive webhooks containing the details of the event to which you have subscribed.

Also, see a product demo or read more in the Help Centre article.

Update webhooks

After you create a webhook, you can change its parameters, name or events.

  1. Go to Integration > Webhooks and find the webhook you want to update.

  2. In the selected webhook line, click three dots and click Edit.

    The Update webhook screen appears.

  3. Change webhook parameters, for example, you can update its description or add and remove events.

  4. Click Update.


Create webhook listener

BVNK sends webhooks for changes on transactions and other entities, so it's a good idea to set up a listener in your service to get the most out of our Payments API.

You can specify your Webhook URL during the creation of a Merchant. To add or change the webhook URL for an existing Merchant, go to the Merchant menu, click Edit, and enter the required address. After you click Save, the Webhook URL will be added along with the generated Secret key.

Click the Merchant's name to see the changes:

Webhooks are sent as an HTTP POST with Content-Type: application/json containing the payload of the object.

Important notes
  • Always check the status of the payment on the API after you receive a webhook, as further details may be required, such as the final amount paid for the transaction about which you have been notified.
  • After you receive the final webhook from BVNK, do not update transactions in your system to prevent duplicate transaction IDs from affecting your customers

Acknowledge events

BVNK expects the 200 status code upon receipt of a successfully sent webhook.

If your webhook script performs any logic after receiving a webhook, to prevent timeouts, you should return a 200 status code before completing the logic.

Webhook retry policy

If BVNK does not receive a 200 status code, the webhook retry policy will kick in. This includes cases where the endpoint returns a non-2xx status code or fails to respond within the 10-second timeout window. After 10 seconds without a successful response, the delivery attempt is considered failed and will trigger the retry process defined by the webhook policy.

The retry policy adds a delay before each retry, starting with a base delay and increasing it with each retry. 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.

To ensure safe and consistent processing, all webhook events include a unique identifier that receivers should use to implement idempotency. This prevents duplicate event handling if the same webhook is retried multiple times due to timeouts or failed responses. The receiving system should detect repeated event IDs and avoid performing the same business action more than once.

Handle duplicate events

Callback endpoints might occasionally receive the same event more than once. We advise you to guard against duplicate event receipts. One way to do this is to log the events you've processed and then exclude the logged ones from further processing.

Validate webhooks

The webhook also contains a signature to allow servers to verify the authenticity of the request using a server-side secret key. The key is displayed in the field Public Key when you create the hook. The signature is present in the headers as the x-signature header.

To calculate the signature, do the following:

  1. Get the payload of the webhook.
  2. Obtain the secret key: go to Manage Account > Manage Merchants, and click a Merchant Name to open its details.

  1. Generate the signature using the Secret Key and payload components. See the examples for different languages below.

    note

    Some legacy webhooks may still require concatenation of the following items to create a signature:

    • Webhook URL
    • content-type
    • Webhook payload

    Note that these webhooks will be soon discontinued.

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;

public class Main {

public static void main(String[] args) throws Exception {
// Secret key from webhook configuration (used as string directly, not Base64 decoded)
String secretKey = "JUL5QkQrpZYwW+Kf03QSrb70CG+ea/j8E/JfslENaXhd0AGBDbAtYYP2MdjkYDqiwjBtrtQXsUIbtAf7IGEGfg==";

// From X-Signature header
String signatureBase64 = "VWEtiJu/7dLrq0ZtXS0HbGDPy6Re86oZeTnEEc9mlxg=";

// Compact JSON payload (no spaces/newlines) - this is what the hook service signs
String payload = "{\"event\":\"bvnk:ledger:report:ready\",\"eventId\":\"0198a8bb-7d56-79ef-92b2-2aed247c21b4\",\"timestamp\":\"2025-08-14T13:18:36.374620938Z\",\"data\":{\"id\":\"8d942264-e27e-44d9-a048-5ed66ac5129f\",\"url\":\"https://bvnk-staging-reports.s3.eu-west-1.amazonaws.com/transaction/8d942264-e27e-44d9-a048-5ed66ac5129f_7b2f87b9-1335-4b1e-bbeb-6a59ba1dc6df.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250814T131836Z&X-Amz-SignedHeaders=host&X-Amz-Credential=AKIAZP6R7NJUFAGFGMNA%2F20250814%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Expires=604800&X-Amz-Signature=5c861e552b3e253be28f8e02c818b3c5e00269b9b50b6d4957d5281825d31a67\",\"type\":\"TRANSACTION\",\"status\":\"READY\"}}";

// Use secret key as UTF-8 bytes directly (as hook service does)
byte[] secretKeyBytes = secretKey.getBytes("UTF-8");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, "HmacSHA256");

// Initialize HMAC signature verification
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKeySpec);

// Generate signature for the payload
byte[] computedSignature = mac.doFinal(payload.getBytes());
String computedSignatureBase64 = java.util.Base64.getEncoder().encodeToString(computedSignature);

// Decode received signature
byte[] receivedSignature = java.util.Base64.getDecoder().decode(signatureBase64);

// Verify signatures match
boolean verified = Arrays.equals(computedSignature, receivedSignature);

System.out.println("Expected signature: " + computedSignatureBase64);
System.out.println("Received signature: " + signatureBase64);
System.out.println("Signature is valid: " + verified);
}
}
Make sure you do not parse your HTTP request into an object and then serialize it.

Instead, provide the webhook raw payload as a string.

The signature will be available in the x-signature header of the webhook. Every new webhook has a unique x-signature header value. Make sure you compare the hash to the correct header.