# Callbacks (Webhooks)

### General information

Our service can send callbacks (or webhooks; we will use the word `callback` further in this article) when some events happen: invoice or channel created, received a payment, processed a payment, etc.

You can configure callbacks in the "Callbacks (Webhooks)" section in the Dashboard.

{% hint style="info" %}
**Keep in mind: 200 HTTP-code, 10 seconds limit**

When you use callbacks be sure that your server always responds with a 200 HTTP-code and do it in less than 10 seconds. If not, our server will retry a callback. Check out our [retry strategy](#retries) to learn how it works.
{% endhint %}

### Validate Callback

When you receive a callback from our service you have to check that this is a valid request. We use signatures for these checks.&#x20;

Every callback has a header **`X-Munzen-Signature`**:

```
X-Munzen-Signature: request_signature
```

This header contains a signature, which generates very similar to API Authentication Signature.&#x20;

#### Signature Validation Example

Here is an example of how to validate a callback signature:

```php
<?php
$secret = 'your_secret_here';

$requestMethod = 'POST'; // always POST for webhooks
$requestBody = '{"data":{"id":"0189175b-e5ac-7050-8750-5c3df2663f94","fees":{"processing_channel":{"amount":"0.00208","currency":"ETH"}},"amount":"0.0052","status":"paid","address":"0x166547C06303db50FE610Be067BCC538AcC1849c","currency":"ETH","channel_id":"0189175a-1219-7216-8165-8d08785a93a5","created_at":"2023-07-02T16:07:25.000000Z","address_tag":null,"address_uri":"ethereum:0x166547C06303db50FE610Be067BCC538AcC1849c?amount=0.0052","external_id":"asdqwe123123123","fiat_amounts":{"EUR":{"fee_amount":"3.65","paid_amount":"9.14"},"UAH":{"fee_amount":"146.51","paid_amount":"366.27"},"USD":{"fee_amount":"3.99","paid_amount":"9.98"}},"external_data":null,"status_reason":null,"received_amount":"0.00312","amount_minus_fee":"0.00312","transaction_hash":"0xb810c95bb842c7642da75e620801e12693a517b17f58e92a4d6c143fde285332","received_currency":"ETH","customer_external_id":"3424523dasdasd","transaction_risk_score":7,"conversion_exchange_rate":null},"type":"channel_payment","event":"deposit_completed","timestamp":1688314046}';
$stringToSign = $requestMethod . $requestBody;

$signature = hash_hmac('sha256', $stringToSign, $secret);
```

#### Our IPs

We recommend you white-list our IPs for callbacks and ignore requests from all other IPs. This will be an additional option to secure your callback endpoint. Here are our IPs:

| Environment | IPs               |
| ----------- | ----------------- |
| Sandbox     | `34.65.94.128/32` |
| Production  | `34.65.94.128/32` |

### Retries

As mentioned above, we use retries in the case when we don't receive a **200 HTTP-code** from your server. To avoid DDoS on your server from our side, we have an increasing time period for callbacks. Here is how it works:

`30 + num ^ 4 + num`, where `num` is the number of retries from 0 to 19.

Full list of retries time periods:

```
0d 00h 00m 30s
0d 00h 00m 32s
0d 00h 00m 48s
0d 00h 01m 54s
0d 00h 04m 50s
0d 00h 11m 00s
0d 00h 22m 12s
0d 00h 40m 38s
0d 01h 08m 54s
0d 01h 50m 00s
0d 02h 47m 20s
0d 04h 04m 42s
0d 05h 46m 18s
0d 07h 56m 44s
0d 10h 41m 00s
0d 14h 04m 30s
0d 18h 13m 02s
0d 23h 12m 48s
1d 05h 10m 24s
1d 12h 12m 50s
```

### Timeouts

We have **10 seconds** limit for every callback response. So if your server will not respond within 10 seconds we will terminate the connection and mark the callback as unsuccessful. We will retry to send this callback again according to our [retries policy](#retries).

Sometimes callback handlers can contain complex business logic and take time to execute. That's why we recommend you save callback data and respond with 200 HTTP code. And after that process callback data in an async way.&#x20;

### Avoid Double-Spending problem

Sometimes the same callback can be handled by your endpoint a few times. So you need to check every callback and try to log them to avoid double crediting your customer's balances.


---

# 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.munzen.io/api-overview/callbacks-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.
