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

# Webhooks

> Configure webhook endpoints to receive HTTP POST requests from Knot.

## Introduction

A webhook is an HTTP request used to provide various events. Knot provides webhooks for updates related to a user's lifecycle in the Knot user experience as well as various asynchronous processes.

To receive webhooks from Knot, set up dedicated endpoints on your server as webhook listeners that can receive POST requests from Knot's `development` and `production` environments respectively.

## Configuring Webhooks

Once you have added endpoints on your server, add these endpoint URLs in your Knot Dashboard [here](https://dashboard.knotapi.com/developers/webhooks). You can configure up to 10 webhook URLs per environment.

The URLs of your dedicated endpoints must be in the standard format of `http(s)://(www.)domain.com/` and must have a valid SSL certificate if https.

Knot sends POST payloads with raw JSON to your webhook URL from the following IP address in all environments (Production & Development): `35.232.249.218/32`. This IP address is subject to change and you will be notified in advance of any changes.

## Webhook Verification

Knot signs all outgoing webhooks so that you can verify the authenticity of any incoming webhooks to your application. This verification process is optional and is not required for your application to handle webhooks from Knot.

<Steps>
  <Step title="Extract the knot-signature header" titleSize="h3">
    Extract the Hash-based Message Authentication Code (HMAC) signature included in the `Knot-Signature` header of the webhook. You will later compare this against your computed signature.
  </Step>

  <Step title="Prepare the hash map" titleSize="h3">
    Collect the following headers and body fields into a hash map. `Content-Length` is the byte length of the entire raw JSON request body, so any tampering with the body (beyond the signed `event` and `session_id` fields) will change this value and invalidate the signature.

    ```javascript theme={"system"}
    const data = {
      "Content-Length": "178",
      "Content-Type": "application/json",
      "Encryption-Type": "HMAC-SHA256",
      "event": "CARD_UPDATED",
      "session_id": "fb5aa994-ed1c-4c3e-b29a-b2a53222e584"
    }
    ```

    <Note>
      Not all webhooks will have a `session_id` in the request body (such as the `MERCHANT_STATUS_UPDATE` webhook). In those scenarios, do not include the `session_id` in the hash map.
    </Note>
  </Step>

  <Step title="Build the signature" titleSize="h3">
    Build the following string from the hash map, concatenating key-value pairs with `|`

    ```
    Content-Length|178|Content-Type|application/json|Encryption-Type|HMAC-SHA256|event|CARD_UPDATED|session_id|fb5aa994-ed1c-4c3e-b29a-b2a53222e584
    ```

    Using your client secret from the [Knot Dashboard](https://dashboard.knotapi.com/), compute an HMAC signature using SHA256 and base64 encode the result.
  </Step>

  <Step title="Compare the signatures" titleSize="h3">
    Compare the signature extracted from the `Knot-Signature` header in the webhook to the signature you computed in the above step and ensure they're the same.
  </Step>
</Steps>

## Retries

If there is a non-200 response or no response within 10 seconds from your webhook listener endpoint, Knot will retry sending the webhook up to two times with a few minutes in between each request.

## Session Metadata

You can attach custom key-value pairs (metadata) to a session, and this metadata will be included in all webhook payloads for that session. This is useful for:

* **Conditional webhook acceptance**: Pass a JWE token, the contents of which can be used to determine whether to accept or reject the webhook payload
* **Request correlation**: Include internal reference IDs for tracking
* **Custom data**: Any string key-value pairs you need echoed back

### How to Attach Metadata

You can attach metadata in two ways:

**Server-side**: Include metadata when calling [Create Session](/api-reference/sessions/create-session):

```bash theme={"system"}
POST /session/create
{
  "type": "card_switcher",
  "external_user_id": "user-123",
  "card_id": "card-456",
  "metadata": {
    "reference_token": "your-jwe-token",
    "internal_ref": "order-789"
  }
}
```

**Client-side**: Pass metadata when opening the SDK. See the [SDK documentation](/sdk/introduction) for platform-specific implementation details. Client-side metadata is merged with any server-side metadata, with client-side values taking precedence for duplicate keys.

### Webhook Payload

When metadata is attached to a session, it appears in the `data.metadata` field of webhook payloads:

```json theme={"system"}
{
  "event": "CARD_UPDATED",
  "session_id": "fb5aa994-ed1c-4c3e-b29a-b2a53222e584",
  "task_id": 25605,
  "external_user_id": "user-123",
  "merchant": {
    "id": 11,
    "name": "Uber"
  },
  "data": {
    "card_id": "card-456",
    "metadata": {
      "reference_token": "your-jwe-token",
      "internal_ref": "order-789"
    }
  },
  "timestamp": 1710864923198
}
```

<Note>
  Metadata is only included when you provide it. If no metadata is attached to the session, the `metadata` field will not appear in the webhook payload.
</Note>

### Constraints

* Maximum **10 keys** per session
* Maximum **500 characters** per value
* Keys and values must be **strings**
