# Creating a webhook

In this tutorial, we'll walk through creating a webhook to listen for new submissions to a contact form on a site. Whenever someone submits this form, Webflow will send a notification to the specified destination. Additionally, we'll cover how to verify that the webhook requests you're receiving are genuinely from Webflow, ensuring secure and reliable communication with your application.

<Note title="Looking for a simpler setup?">
  If you'd prefer a way to set up webhooks without using the API, you can easily [configure them through the Webflow dashboard](https://university.webflow.com/lesson/intro-to-webflow-apis?topics=cms-dynamic-content#how-to-create-a-webhook). Please note, that webhooks created through the dashboard will not include the request headers needed to [validate request signatures.](#validating-request-signatures)
</Note>

#### Prerequisites

* A [site token](/data/reference/site-token) or bearer token from a Webflow [Data Client App](/data/docs/getting-started-apps) with the `forms:read` scope.
* A Webflow test site. You can use the [Biznus template](https://webflow.com/templates/html/biznus-retail-website-template) to quickly set up a site equipped with a contact form.
* A service to accept an HTTPS request. While we'll be using [https://webhook.site](https://webhook.site) in this tutorial, you're free to choose any platform.

<br />

<Accordion title="Step 1. Create a form">
  Before we get started working with the API, we'll first need to create a form and publish our site. If you already have a working form on your site, you can skip this step. To create a site with a form, we'll use the <a href="https://webflow.com/dashboard/sites/new?t=5e864888a8dec40670d77ac4">Biznus template</a>, which already has a <a href="https://biznus-template.webflow.io/contact">form</a> on its contact page.

  1. **Clone the [Biznus template](https://webflow.com/dashboard/sites/new?t=5e864888a8dec40670d77ac4)** to your development Workspace.

  2. **Go to the Contact Page** to view your form. Here, you can review your form's fields. Ensure each field has a unique name. These field names will be used as keys in the webhook's payload.
     ![Form Fields](https://files.buildwithfern.com/https://webflow.docs.buildwithfern.com/3f45f69aca87ea3c60972974e53a7c72a80b4b8388b2542172397cc692223eb8/assets/images/6f39396-Screen_Shot_2022-11-08_at_1.42.30_PM.png)

  3. **Publish the site** by clicking the publish button in the top right corner.
</Accordion>

<Accordion title="Step 2. Create a webhook">
  Webhooks require the following elements to function:

  * **Site ID:** The unique identifier of your Webflow site.
  * **Trigger Type:** Specific event the webhook will monitor.
  * **Destination URL:** Unique URL prepped to accept HTTP requests.

  Once we have these elements, we can create the webhook by sending a `POST` request to the [Create Webhook](https://developers.webflow.com/data/reference/webhooks/create) endpoint.

  1. **Get the Site ID.** There are two ways to get your Site ID, you can access the ID via site settings, or send a request to the [List Sites](https://developers.webflow.com/data/reference/sites/list) endpoint.

     <Tabs>
       <Tab title="Site Settings">
         1. In the designer, click the Webflow Icon in the top left corner, and select "Site Settings" from the menu.

         2. In your site settings, scroll down to the "Overview" section to find your Site ID
            ![Site ID location in settings](https://files.buildwithfern.com/https://webflow.docs.buildwithfern.com/e3071f6add47d66472945082d7cd25929679b0781c24f75b145232439b4c9358/assets/images/7bbb258-Screenshot_2024-07-29_at_2.49.21_PM.png)
       </Tab>

       <Tab title="API Request">
         1. Send a request to the [List Sites](https://developers.webflow.com/data/reference/sites/list) endpoint.

            <CodeBlocks>
              ```curl cURL
              curl --request GET \
                        --url https://api.webflow.com/v2/sites \
                        --header 'accept: application/json' \
                        --header 'authorization: Bearer YOUR_ACCESS_TOKEN'
              ```

              ```javascript node.js
              const webflow = new WebflowClient({ accessToken: "YOUR_ACCESS_TOKEN" });
              async function fetchSites() {
                try {
                  const sites = await webflow.sites.get();
                  console.log(sites);
                } catch (error) {
                  console.error("Error fetching sites:", error);
                }
              }
              fetchSites();
              ```
            </CodeBlocks>

         2. Review the response to find the `displayName` of your test site and its corresponding `id`.

            ```json Response
            {
              "sites": [
                {
                  "id": "42e63e98c9a982ac9b8b741",
                  "workspaceId": "42e63fc8c9a982ac9b8b744",
                  "createdOn": "1979-10-12T12:00:00.000Z",
                  "displayName": "Heart of Gold Spaceship",
                  "shortName": "heart-of-gold",
                  "lastPublished": "2023-04-02T12:42:00.000Z",
                  "previewUrl": "https://dev-assets.website-files.com/42e63e98c9a982ac9b8b741/197910121200.png",
                  "timeZone": "DeepSpace/InfiniteImprobability",
                  "parentFolderId": "1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6",
                  "customDomains": [
                    {
                      "id": "589a331aa51e760df7ccb89e",
                      "url": "heartofgold.galaxy"
                    }
                  ],
                  "locales": {
                    "primary": {
                      "id": "653fd9af6a07fc9cfd7a5e57",
                      "cmsLocaleId": "653ad57de882f528b32e810e",
                      "enabled": true,
                      "displayName": "English - Heart of Gold Standard",
                      "redirect": false,
                      "subdirectory": "/en",
                      "tag": "The Ultimate Answer"
                    },
                    "secondary": [
                      {
                        "id": "653fd9af6a07fc9cfd7a5e58",
                        "cmsLocaleId": "653ad57de882f528b32e810g",
                        "enabled": true,
                        "displayName": "Betelgeusian - Vogon Liaison",
                        "redirect": true,
                        "subdirectory": "/bet",
                        "tag": "Vogon"
                      },
                      {
                        "id": "653fd9af6a07fc9cfd7a5e59",
                        "cmsLocaleId": "653ad57de882f528b32e810h",
                        "enabled": false,
                        "displayName": "Magrathean - Custom Planet Designs",
                        "redirect": true,
                        "subdirectory": "/mg",
                        "tag": "Magrathean"
                      }
                    ]
                  }
                },  ]
            }
            ```
       </Tab>
     </Tabs>

  2. **Get your destination URL.** Navigate to [webhook.site](https://webhook.site) and copy your unique URL. This URL will be used as the destination where Webflow will send webhook events.
     ![Screenshot showing webhook.site interface with unique URL](https://files.buildwithfern.com/https://webflow.docs.buildwithfern.com/016bf242fb68ded0df190fc26dc9210e727b87844ce8ce16e31b665bdcc1bd50/assets/images/1428146-Screenshot_2024-07-30_at_12.54.18_PM.png)

  3. **Send a `POST` request to the [Create Webhook](https://developers.webflow.com/data/reference/webhooks/create) endpoint.** In the request, you'll include the `site_id`, `url`, and `triggerType` of `form_submission`.

     <CodeBlocks>
       ```curl cURL
       curl -X POST "https://api.webflow.com/sites/YOUR_SITE_ID/webhooks" \
               -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
               -H "Content-Type: application/json" \
               -d '{
                     "triggerType": "form_submission",
                     "url": "https://your-webhook-url.com"
                   }'
       ```

       ```javascript JavaScript
       const WebflowClient = require('webflow-api'); // Import Webflow API client

       async function createWebhook(req) {
         const accessToken = req.accessToken; // Get access token from the request
         const siteId = "YOUR_SITE_ID"; // Replace with your actual Site ID

         const webflow = new WebflowClient({ accessToken }); // Initialize Webflow client

         try {
           const webhook = await webflow.webhooks.create(siteId, {
             triggerType: 'form_submission', // Trigger type for the webhook
             url: "https://your-webhook-url.com" // Replace with your webhook URL
           });
           console.log('Webhook created successfully:', webhook);
           return webhook;
         } catch (error) {
           console.error('Error creating webhook:', error.message);
         }
       }

       createWebhook(req); // Moved function call outside the function definition
       ```
     </CodeBlocks>

     Additionally, the `form_submission` trigger supports a `filter` parameter, allowing you to specify the name of the form you'd like to receive notifications for. This is particularly helpful if you have multiple forms on a site.

     <Info title="Use our interactive API Docs to send requests">
       You can also use the interactive API Reference to quickly send a POST request to the [Create Webhook](/data/reference/webhooks/create) endpoint without writing any code.
     </Info>

  4. **Review the response.** After successfully establishing your webhook, you should receive a confirmation similar to the one shown below:
     <CodeBlocks>
       ```json Successful response
       {
         "id": "582266e0cd48de0f0e3c6d8b",
         "triggerType": "form_submission",
         "siteId": "562ac0395358780a1f5e6fbd",
         "workspaceId": "4f4e46fd476ea8c507000001",
         "createdOn": "2022-11-08T23:59:28.572Z",
         "lastTriggered": "2023-02-08T23:59:28.572Z",
         "filter": null,
         "url": "https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f",
         "secretKey": "2b4acfd1c5518bf03c73a4889d197d77251353857c22694bf150b9e3402ba15f" 
         // 👆 The secret key is only present if using a Site API key created from the Site Dashboard
       }
       ```
     </CodeBlocks>
</Accordion>

<Accordion title="Step 3. Send a test submission">
  Once you've successfully created the Webhook to listen for new form submissions, you can test it by navigating to the form on your site and submitting a response.

  Once you've submitted a response, head over to [webhook.site](https://webhook.site) to view the `POST` request from Webflow. If the request is successful, you'll see the Request Details, Headers, and Payload sections. These details should match the JSON object shown below.

  <CodeBlocks>
    ```json JSON
    Content-Type: application/json
    x-webflow-timestamp: 1722370035277
    x-webflow-signature: cb6162d8daf6573c658805a5f431adab25f56faf6c601935067d3957a161dfeb
    {
      "triggerType": "form_submission",
      "payload": {
        "name": "Email Form",
        "siteId": "65427cf400e02b306eaa049c",
        "data": {
          "Email 2": "hello@gmail.com"
        },
        "submittedAt": "2024-07-30T20:07:15.220Z",
        "id": "66a947f35b9d7ba400e22733",
        "formId": "65429eadebe8a9f3a30f62d7"
      }
    }
    ```
  </CodeBlocks>

  <Info>
    Notice the headers included in the response: `x-webflow-timestamp` and `x-webflow-signature`. These headers are crucial for verifying the authenticity of the webhook.
  </Info>
</Accordion>