> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yapily.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks Get Started

> Get started with Yapily Webhooks. Register webhook endpoints, verify event signatures, and handle payment and consent event notifications in your backend application.

<Note>
  Webhooks is available as a [Private Beta version](/getting-started/overview#private-beta).
  Please contact your Customer Success Manager if you would like to access it.
</Note>

This document explains how to set up a Webhook that will notify you whenever the Event Category you subscribed to is triggered. Once you understand how to set up this Webhook you will know how to set up all Webhooks.

Setting up any Webhook requires you to:

* Create an endpoint on a secure server that can process HTTPS requests.
* Making sure the endpoint is public and can be reached from outside your system.
* Authenticate with Yapily API and receive a Yapily API Token
  * if you don't have a Yapily account then please our [Account Setup Guide](/getting-started/get-started)

If you want to understand better how Webhooks work in Yapily Platform then please check our [Webhook Introduction](/tools-and-services/webhooks/introduction) page.

## Retrieve Webhook Event Categories

Before we register a Webhook we need to get a list of available Webhook Event Categories.

* Call endpoint `GET /webhook/events/categories` in order to retrieve all available Event Categories
* Choose the one you want to subscribe to and use them in the [Webhook Registration](/tools-and-services/webhooks/get-started#webhook-registration) call

## Webhook Registration

You can register a Webhook with one or multiple Webhook Event Categories. In order to register a Webhook and to start receiving Webhook Events in your application follow the steps bellow:

* After retrieving all webhook topics, and choosing the ones the webhook should be triggered for
* Build a request using the topics chosen and call `POST /webhook/events`
* From the successful response of the call get the webhook secret
* Store the webhook secret for further validating the payload signature when receiving events

<Info>
  This is the only API call that would display the webhook secret, you will not be able to retrieve the secret using the API after registration call, please store it if you want to use the webhook signature validation feature
</Info>

### Restrictions

There are a few restrictions to be aware of when registering a new Webhook:

* An application can register up to 10 webhooks, any further attempts will result in a 406 response
* A callback URL must not contain any query parameters, otherwise a 400 response is returned
* The metadata must be under 10kB, otherwise a 400 response is returned

## Retrieving registered webhooks

* Get a Yapily access token
* Call endpoint `GET /webhook/events` it will return all registered webhooks to your current application

## Resetting webhook secret

In situation when the secret gets compromised you have the option to reset it using the API

* Get a Yapily access token
* Reference the webhook id you received when registering the webhook
* Call endpoint `POST /webhook/secrets/{webhook_id}` it will reset the secret and return the secret in the response

<Info>
  You have the option to reset the secret with a delay, meaning that for the time specified in the reset secret request we will be sending both signatures in the event request giving you time to rotate the secret on your side without any downtime
</Info>

## Deleting a webhook

* Get a Yapily access token
* Call endpoint `DELETE /webhook/events/{webhook_id}` it will return a confirmation that the webhook was deleted

***

## Webhook for Sub-Application

In cases when you are using [Application Management for Reseller & Merchants](/getting-started/application-management) all the steps and limitation remains the same and for each of the request the following changes need to be made:

* Set a `sub-application` header when executing the http request, with the value being sub-application id
* If the request requires an `applicationId` field in the request, then the value of the field should be the sub-application id

***

## Validating an Event signature

To protect your server from unauthorised webhook events, all payloads are signed using HMAC algorithm `HmacSHA256`.

When receiving an event do the following:

* Read the signature from the headers `webhook-signature`. If you are rotating keys you will receive `webhook-rotation-signature` too
* Assuming you saved the key provided to you during webhook registration or key rotation
* Read the incoming request body stream directly into a string
* Use the string to generate the HMAC signature using algorithm `HmacSHA256`
* Compare the hash you got in the headers with the one generated

<Info>
  Do not map it to any structure that may affect the order or structure of the payload before generating the signature
</Info>

### Code Example

#### 1. java

```java theme={null}
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.hc.client5.http.utils.Hex;

public class EvenPayloadValidation {

  private static final String ALGORITHM = "HmacSHA256";
  private static final String KEY = "somekey"; // key received while registering webhook

  public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {

    String eventPayload = "response body"; // response body
    Map<String, String> headers = new HashMap<>();  // response headers

    byte[] keyBytes = KEY.getBytes();

    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM);
    Mac mac = Mac.getInstance(ALGORITHM);
    mac.init(secretKeySpec);

    String signedPayload = Hex.encodeHexString(mac.doFinal(eventPayload.getBytes()));

    if (headers.get("webhook-signature").equalsIgnoreCase(signedPayload) ||
        headers.get("webhook-rotation-signature").equalsIgnoreCase(signedPayload)) {
      System.out.println("valid payload");
    } else {
      System.out.println("invalid payload");
    }
  }
}
```

#### 2. javascript

```javascript theme={null}
const crypto = require('crypto');

function validateEventPayload(eventPayload, headers) {
  const ALGORITHM = 'sha256';
  const KEY = 'somekey';  // key received while registering webhook

  const keyBytes = Buffer.from(KEY, 'utf-8');

  const hmac = crypto.createHmac(ALGORITHM, keyBytes);
  hmac.update(eventPayload, 'utf8');
  const signedPayload = hmac.digest('hex');

  const webhookSignature = (headers['webhook-signature'] || '').toLowerCase();
  const rotationSignature = (headers['webhook-rotation-signature'] || '').toLowerCase();

  if (webhookSignature === signedPayload || rotationSignature === signedPayload) {
    console.log("valid payload");
  } else {
    console.log("invalid payload");
  }
}

// usage
const eventPayload = "response body";   // response body
const headers = {                       // response headers
  "webhook-signature": "expected_signature_here",
  "webhook-rotation-signature": "another_signature_here"
};

validateEventPayload(eventPayload, headers);
```

#### 3. python

```python theme={null}
import hmac
import hashlib

def validate_event_payload(event_payload, headers):
    ALGORITHM = 'sha256'
    KEY = 'somekey'  # key received while registering webhook

    key_bytes = KEY.encode('utf-8')

    mac = hmac.new(key_bytes, event_payload.encode('utf-8'), hashlib.sha256)
    signed_payload = mac.hexdigest()

    webhook_signature = (headers.get('webhook-signature') or "").lower()
    rotation_signature = (headers.get('webhook-rotation-signature') or "").lower()

    if webhook_signature == signed_payload or rotation_signature == signed_payload:
        print("valid payload")
    else:
        print("invalid payload")

# usage
event_payload = "response body"                 # response body
headers = {                                     # response body
    "webhook-signature": "expected_signature_here",
    "webhook-rotation-signature": "another_signature_here"
}

validate_event_payload(event_payload, headers)
```
