# Source: https://docs.frigade.com/api-reference/webhooks.md

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

# Webhooks

Webhooks allow you to receive notifications from Frigade when certain events occur.
You can use webhooks to receive notifications about your users when they start a Flow and as they progress through it.

## Creating a webhook

To add a new webhook, open the **Developer** page from the left sidebar, pick the **Webhooks** tab and click the "New webhook" button.

<Frame>
  <img src="https://mintcdn.com/frigade-docs/vb0YqHQGpTytLgI7/images/platform/webhooks.png?fit=max&auto=format&n=vb0YqHQGpTytLgI7&q=85&s=f8b3b7e5dbf1d0b133c3e0a0787309bc" data-og-width="1399" width="1399" data-og-height="835" height="835" data-path="images/platform/webhooks.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/frigade-docs/vb0YqHQGpTytLgI7/images/platform/webhooks.png?w=280&fit=max&auto=format&n=vb0YqHQGpTytLgI7&q=85&s=38e3d45ef2decfaadf6f40a618f5ed46 280w, https://mintcdn.com/frigade-docs/vb0YqHQGpTytLgI7/images/platform/webhooks.png?w=560&fit=max&auto=format&n=vb0YqHQGpTytLgI7&q=85&s=daf73ded7c324f9ce557f4debdb1f7aa 560w, https://mintcdn.com/frigade-docs/vb0YqHQGpTytLgI7/images/platform/webhooks.png?w=840&fit=max&auto=format&n=vb0YqHQGpTytLgI7&q=85&s=8b7811f8060afe7d32b07efc5fc9b5c6 840w, https://mintcdn.com/frigade-docs/vb0YqHQGpTytLgI7/images/platform/webhooks.png?w=1100&fit=max&auto=format&n=vb0YqHQGpTytLgI7&q=85&s=a12a11b1e1a9250ad50daea4978f758d 1100w, https://mintcdn.com/frigade-docs/vb0YqHQGpTytLgI7/images/platform/webhooks.png?w=1650&fit=max&auto=format&n=vb0YqHQGpTytLgI7&q=85&s=b106460424f04cb8976ada82addcaff5 1650w, https://mintcdn.com/frigade-docs/vb0YqHQGpTytLgI7/images/platform/webhooks.png?w=2500&fit=max&auto=format&n=vb0YqHQGpTytLgI7&q=85&s=c1f68f6715a84281bc1953bce373c776 2500w" />
</Frame>

## Supported events

The following events are currently supported:

<ParamField body="flowResponse.startedFlow">When a user starts a Flow</ParamField>
<ParamField body="flowResponse.completedFlow">When a user completes a Flow</ParamField>
<ParamField body="flowResponse.skippedFlow">When a user dismisses/skips a Flow</ParamField>
<ParamField body="flowResponse.startedStep">When a user starts a Step in a Flow</ParamField>
<ParamField body="flowResponse.completedStep">When a user completes a Step in a Flow</ParamField>

## Webhook payload

The payload of the message includes the type of the event in the `type` property.

The data property contains the actual payload sent by Frigade.
The payload can be a different object depending on the event type.

### Schema

```typescript  theme={"system"}
{
  // Event type identifier
  type: string;  // e.g. "flowResponse.completedFlow"
  
  // Timestamp when the event occurred (ISO 8601)
  time: string;  // e.g. "2024-08-21T16:31:36.207Z"
  
  // Request timeout in milliseconds
  timeout: number;

  // User information
  user: {
    // The user id in your system. This will match the `foreignUserId` field in the data object.
    id: string;
    // The name of the user
    name: string;
    // The email of the user
    email: string | null;
  };

  // Flow information
  flow: {
    // Flow ID, for example: flow_8Lq7hAqA
    id: string;

    // Flow name, for example: "NPS Survey"
    name: string;
  };

  // Detailed response data
  data: {
    // Step-specific data, keyed by stepId
    [stepId: string]: {
      [fieldName: string]: any;
    };

    // Response ID
    id: string;

    // Flow ID
    flowId: string;

    // Flow slug
    flowSlug: string;

    // Numeric Frigade user ID
    userId: number;

    // Frigade user slug
    userSlug: string;

    // Action type: COMPLETED_FLOW, SKIPPED_FLOW, COMPLETED_STEP, SKIPPED_STEP
    actionType: string;

    // Step ID
    stepId: string;

    // ISO 8601 timestamp
    createdAt: string;

    // Foreign user ID. This will match your own internal user ID provided to Frigade.
    foreignUserId: string;

    // Whether the flow is blocked
    blocked: boolean;

    // Whether the flow is hidden
    hidden: boolean;

    // Additional data collected, such as form data in a stringified JSON object.
    data: string;
  };
}
```

The below example shows the payload for a `flowResponse.completedFlow` event for the [NPS Survey](/component/survey/nps) component with flattened data fields:

```json  theme={"system"}
{
  "timeout": 1000,
  "data__nps-feedback-page__nps-feedback-text": "I love the service!",
  "data__nps-score-page__nps-score": 10,
  "data__id": "flowResponse_uPzbTOayngU00Vzc",
  "data__flowId": "flow_8Lq7hAqA",
  "data__flowSlug": "flow_8Lq7hAqA",
  "data__userId": 53526,
  "data__userSlug": "user_qnsDyTeZxP2sl12Q",
  "data__actionType": "COMPLETED_FLOW",
  "data__data": "{}",
  "data__stepId": "nps-feedback-page",
  "data__blocked": false,
  "data__hidden": false,
  "user__name": "",
  "user__email": null,
  "user__id": "abcdefgh",
  "flow__id": "flow_8Lq7hAqA",
  "flow__name": "NPS Survey",
  "type": "flowResponse.completedFlow",
  "data": {
    "nps-feedback-page": {
      "nps-feedback-text": "I love the service!"
    },
    "nps-score-page": {
      "nps-score": 10
    },
    "id": "flowResponse_uPzbTOayngU00Vzc",
    "flowId": "flow_8Lq7hAqA",
    "flowSlug": "flow_8Lq7hAqA",
    "userId": 53526,
    "userSlug": "user_qnsDyTeZxP2sl12Q",
    "actionType": "COMPLETED_FLOW",
    "data": "{}",
    "stepId": "nps-feedback-page",
    "createdAt": "2024-08-21T16:31:36.187Z",
    "foreignUserId": "abcdefgh",
    "blocked": false,
    "hidden": false
  },
  "time": "2024-08-21T16:31:36.207Z",
  "user": {
    "name": "",
    "email": null,
    "id": "abcdefgh"
  },
  "flow": {
    "id": "flow_8Lq7hAqA",
    "name": "NPS Survey"
  }
}
```

## Verifying webhooks

When you create a webhook, Frigade will generate a secret key for you. You can use this key to verify that the webhook is coming from Frigade.

<Note>
  If you don't verify the request, your app will be susceptible to a number of attacks since your webhook endpoint is open to the public.
</Note>

To verify the request, you need to calculate the HMAC SHA256 digest of the JSON-encoded `data` field using the secret key as the key and compare it to the value in the `X-Webhook-Signature` header. The signature is base64 encoded.
Note that when JSON-encoding the `data` field it needs to match the order of the keys in the payload and not contain any whitespace between the keys and values.

For example, in Node.js, you can do it like this:

```ts  theme={"system"}
const crypto = require('crypto');

const payload = '{"type":"flowResponse.completedStep",....}}'
const secret = 'my-secret' // Find this in the webhook settings in the Frigade dashboard
function verifySignature(secret, payload) {
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(Buffer.from(payload, 'utf-8'));
  const digest = hmac.digest('base64');
  return digest;
}

const signature = verifySignature(secret, payload);

if (signature !== payload.signature) {
  throw new Error('Invalid signature');
}
```

## Verifying timestamps

The `time` field in the payload is the time when the event occurred. You can use this field to verify that the request is not a [replay attack](https://en.wikipedia.org/wiki/Replay_attack) by ignoring older events.

## Retrying failed requests

Frigade will retry failed requests up to 5 times with an exponential backoff strategy.

## Common fields

The following fields are available in all Frigade webhooks (shown in flattened format):

* `flow__id`: The ID of the Flow that triggered the webhook
* `flow__name`: The name of the Flow that triggered the webhook
* `user__id`: The ID of the user that triggered the webhook
* `user__name`: The name of the user that triggered the webhook (if available)
* `user__email`: The email of the user that triggered the webhook (if available)