# Webhooks

## Overview

### Accounts & Contacts

The Webhook connector supports both syncing into Accounts & Contacts if Contacts are enabled on your GoodFit account. GoodFit will send a webhook request for each new and modifed record in your dataset.

You can specify a webhook URL to send the events to, separately for companies and contacts. If you dont wish to recieve events for contacts, you can leave 'Webhook contacts URL' blank.

<figure><img src="/files/W276thZ3airSbHjOKeDv" alt=""><figcaption><p>Webhook Settings Pannel</p></figcaption></figure>

### Payloads

Records are sent as JSON payloads to your webhook endpoints. The exact schema of these messages depends on the configuration of your GoodFit account. You can see an exact example of payloads for each record type in the webook settings panel.

#### Webhook Batch Size

You're able to specify whether you want records to be sent individually or in batches. The value can be set in **Webhook Batch Size** field. The maximum batch size supported is 200 records in a single call.

### Authentication

GoodFit supports 2 optional methods for securing the webhook integration, depending on the nature of the platform you are sending data to:

* HTTP headers. This allows you to add additional HTTP headers that are included in the HTTP webhook request we send to your endpoints. For example you can include an API key or similar in the Authoriziation header.
* HMAC signature. This allows the webhook message to be cryptographically signed with a shared key, known only to the sender (GoodFit) and your application. The secret is never transferred in the message and cannot be intercepted.

#### HMAC Authentication

Before the source app sends an HTTP request via the webhook, it hashes the payload (request body) with HMAC using the shared secret key. The resulting hash is then bundled into the HTTP request as a header, and the entire request (header and body) is sent to the webhook endpoint.

Upon receiving the HTTP request, the destination app hashes the body with the secret key and then compares the result to the hash provided in the header. If the values match, the destination app knows the data is legit and processes it. If the values do not match, the destination app rejects the data.

If someone tries to spoof the payload without knowing the shared key, they won't be able to generate a valid hash.

In enabled, by pasting the shared key into the webhook settings panel, GoodFit will sign the JSON payload as a string, using the shared secret key and include the SHA256 hash into the `x-goodfit-hmac-sha256` header.

The exact implementation of this is left to your system, however an example may be:

```
const signatureHeader = 'x-goodfit-hmac-sha256'
const signatureAlgorithm = 'sha256'
const encodeFormat = 'hex'
const hmacSecret = process.env.WEBHOOK_SECRET

app.post('/webhook', (req, res) => {
  // Create digest with payload + hmac secret
  const hashPayload = req.rawBody
  const hmac = crypto.createHmac(signatureAlgorithm, hmacSecret)
  const digest = Buffer.from(signatureAlgorithm + '=' + hmac.update(hashPayload).digest(encodeFormat), 'utf8')
  
  // Get hash sent by the provider
  const providerSig = Buffer.from(req.get(signatureHeader) || '', 'utf8')


  // Compare digest signature with signature sent by provider
  if (providerSig.length !== digest.length || !crypto.timingSafeEqual(digest, providerSig)) {
    res.status(401).send('Unauthorized')
  }else{
    // Webhook Authenticated 
    // process and respond...
    res.json({ message: "Success" })
  }
})
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.goodfit.io/goodfit-docs/product/integrations/webhooks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
