# Webhooks

It is a good idea to create a webhook listener page on your website. The IPN listener page contains a custom script or a program that gets messages, validates them with Coindirect, and then passes them to various backend applications for processing.&#x20;

You can specify your Webhook URL on the Settings -> Manage merchants page in your business account.

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

Handling webhooks correctly is crucial to make sure your integration’s business logic works as expected.

![](/files/yjEAZriluiDBG5zVaMmh)

{% hint style="danger" %}
It is highly recommended to validate payment statuses and amounts before acting inside your system.
{% endhint %}

{% hint style="danger" %}
No under circumstances should you completely rely only on webhooks when finalizing payments on your side - please do make an additional call to our API to retrieve the payment details such as its status and the amount that the payment resulted in.
{% endhint %}

{% hint style="danger" %}
Once you finalize the payment on your side, please ensure that no more transactions will appear on the customer's balance in case you receive further webhooks with the same payment `UUID` - this is to avoid potential issues with duplicate balance transactions.
{% endhint %}

### Acknowledge events immediately

If your webhook script performs complex logic or makes network calls, it is possible that the script would time out before Coindirect sees its complete execution. Ideally, your webhook handler code (returning a `200` status code) is separate from any other logic you do for that event.

### Handle duplicate events

Callback endpoints might occasionally receive the same event more than once. We advise you to guard against duplicated event receipts. One way of doing this is logging the events you’ve processed, and then not processing the logged ones.

### Webhooks validation

Webhooks and redirects contain a signature in order for servers to verify the authenticity of the request using a server-side secret key.

For example, if the Merchant ID secret was XYZ, the signature is calculated as follows:

```javascript
var payload = {name:'value',amount:100};
var dataToHash;
if(redirect) {
    dataToHash = JSON.stringify(payload);
}
if(webhook) {
    dataToHash = requestUri; /* The URI of this webhook eg: /my-path on https://mydomain.com/my-path */
    dataToHash += queryString; /* eg: myparam=1 on https://mydomain.com/my-path?myparam=1 */
    dataToHash += contentType; /* eg: application/json */
    dataToHash += JSON.stringify(payload);
}
var hasher = CryptoJS.HmacSHA256(dataToHash, "XYZ");
var hashInHex = CryptoJS.enc.Hex.stringify(hasher);
document.getElementById('output').innerHTML = 'Data to hash: '+dataToHash+"<br/>Resulting signature: "+hashInHex;
```

In redirects, this is included in the signature form parameter. In webhooks, this is included as a header `x-signature`, e.g.:

```javascript
"x-signature": "00c99ee5771db439d083ef59a39b1edfc2cfcb13561c080b957b46b6fcb7b115"
```

Every new webhook will have a new value of the `x-signature` header. Make sure you are comparing the hash to the right header.

You can obtain your Merchant ID Secret key on the "Merchant Details" page in your business account.

{% content-ref url="/pages/-MgjOrWI4tKOXZTK8zGK" %}
[Payment Webhooks](/guides/payments-how-to/payment-webhooks.md)
{% endcontent-ref %}

{% content-ref url="/pages/-MhDekbpqXzi0JbBQYSI" %}
[Channel Webhooks](/guides/channels-how-to/channel-webhooks.md)
{% endcontent-ref %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.coindirect.com/guides/webhooks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
