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 Webhooks page from the left sidebar in the Frigade dashboard and click the “New webhook” button.

Supported events

The following events are currently supported:

flowResponse.startedFlow
When a user starts a Flow
flowResponse.completedFlow
When a user completes a Flow
flowResponse.skippedFlow
When a user dismisses/skips a Flow
flowResponse.startedStep
When a user starts a Step in a Flow
flowResponse.completedStep
When a user completes a Step in a Flow

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

{
  // 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 with flattened data fields:

{
  "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.

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.

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:

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 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)