# Webhooks ## Basics Merchant systems can receive real-time notifications from the xMoney platform via webhooks. Currently, the available events are: - **Order payment confirmation** - **Order cancellation** The webhook URL is specified using the `callback_url` field when creating an order. ### Response Handling & Retries Webhook requests must respond with an **HTTP 2xx status** to indicate success. Any other response or a lack of response is considered a failure, triggering a retry mechanism. xMoney retries up to **15 times** using an exponential backoff following a Fibonacci sequence: 1. First retry: **1 minute** after failure 2. Second retry: **2 minutes** after the first retry 3. Third retry: **3 minutes** after the second retry 4. ... up to 987 minutes (~16 hours 27 minutes) after the last failure If all retries fail, an email notification with error details is sent. ### Security & Authentication All webhook requests from xMoney are **signed** using a Webhooks Secret for validation. - Webhooks are automatically set up and validated in our integrations. - For custom integrations, we provide [**libraries**](/guides/crypto/integrations#libraries) for request validation. - Each webhook request is **signed** to prevent unauthorized access. ## Events Events notify merchants of order-related activities in real time. Webhooks deliver these events to the specified `callback_url`. ### Supported Events | Event Name | Description | | --- | --- | | `ORDER.PAYMENT.RECEIVED` | Payment successfully confirmed. | | `ORDER.PAYMENT.CANCELLED` | Payment was canceled. | ## Verifying Events To ensure authenticity, webhook events are signed using **HMAC SHA256** with the Webhooks Secret as the key. The payload is **sorted alphabetically** before signing. ### Example Payload ```json { "event_type": "ORDER.PAYMENT.RECEIVED", "resource": { "reference": "1400012634", "amount": "10.8200", "currency": "EUR" }, "signature": "5ef8a5994e917c14479b31f690d4d2a023dfcc6059081504e3087977b21580ab", "state": "completed" } ``` ### Ordered Payload for Signing ```json { "event_type": "ORDER.PAYMENT.RECEIVED", "resource": { "amount": "10.8200", "currency": "EUR", "reference": "1400012634" }, "state": "completed" } ``` ### Signing Process ```bash joined_payload="event_typeORDER.PAYMENT.RECEIVEDresourceamount10.8200resourcecurrencyEURresourcereference1400012634statecompleted" signed_payload=$(echo -n "$joined_payload" | openssl dgst -sha256 -hmac "$secret") ``` The resulting signature should match the one in the webhook request. For a PHP validation example, see [this reference](https://github.com/utrustdev/utrust-php/blob/e400f219b73cced5b184f2f15eded3c8654dce3c/src/Webhook/Event.php#L75). ## Response & Retries Webhook responses must follow these rules: - **Success (200 OK)** → `{ "success": true }` (optional JSON response) - **Invalid signature or malformed request (400 Bad Request)** - **Internal processing errors (500 Internal Server Error)** If the webhook fails, retries occur as per the Fibonacci backoff schedule, up to 15 times. After that, an email notification is sent with failure details.