# Guide to Fireberry Webhooks: Features and Best Practices

Fireberry webhooks let your CRM push changes to other systems: a new lead account, an updated deal, a closed ticket. If you want Fireberry records to land in a messaging channel, a mailing system or your own backend the moment an automation fires, a webhook action is how you get them there.

This guide covers how Fireberry webhook automations are built, what your endpoint actually receives, how to authenticate requests Fireberry doesn't sign, the rule that switches failing automations to Draft, and the best practices for a production receiver.

## What are Fireberry webhooks?

Fireberry, the CRM formerly known as Powerlink, has no standalone webhook subscription. Webhooks are an action inside an automation. An automation has a **Type** (the record type), a **When** (the trigger, such as *Account is created*), an optional **If** filter, and one or more actions under **Then**. Add a **Webhook** action, and Fireberry sends an HTTP request each time the automation runs.

You configure every part of that request yourself:

* **Request Method**: `POST`, `GET`, `PUT`, `DELETE` or `PATCH`.
* **URL**: the full URL including the scheme. Fireberry recommends `https://`.
* **Header**: any number of key/value pairs.
* **Body**: free text, usually JSON. There is no body for `GET`.

The URL, headers and body can all include field references from the triggering record, inserted with the `{ }` button.

Because you write the request, Fireberry adds no envelope, no event type field and no Fireberry-specific header. Your endpoint receives exactly what the action sends. Fireberry doesn't sign it, either. The way to authenticate a request is to add a secret header to the action, which is what Fireberry's own article expects when it says most webhooks need "some sort of authorization or API token" in the header.

## Fireberry webhook features

| Feature | Details |
| --- | --- |
| Configuration | A **Webhook** action under **Then** in an automation |
| Trigger | The automation's **Type**, **When** and **If** settings |
| Methods | `POST`, `GET`, `PUT`, `DELETE`, `PATCH` |
| Headers | Unlimited key/value pairs, with field references |
| Body | Free text (typically JSON), with field references. Not available for `GET` |
| Event types | None defined by Fireberry. You put whatever identifies the event into the body |
| Authentication | A secret header you add to the action |
| Signature | None |
| Logging | Each send adds a system log to the related record's stream |
| Failure handling | The automation is set to **Draft** after repeated consecutive error responses |
| Retries and timeout | Not documented |
| Source IPs | Not published |

## Designing the payload

With no event types to subscribe to, you decide what the receiver gets. A pattern that works well is to include an explicit event name and the record's ID in every body, so one endpoint can serve many automations:

```json
{
  "event": "account.created",
  "record": {
    "id": "<account id field reference>",
    "name": "<account name field reference>",
    "status": "<status field reference>"
  }
}

```

The `event` value here is your own label for the automation, not something Fireberry sends. Insert the real values with the `{ }` field reference button. Keep the body valid JSON once the field references are filled in: a field value containing a quote or line break can break a hand-written template, so test with realistic records. Add a `Content-Type: application/json` header so receivers parse the body correctly.

> **Inspect Fireberry webhooks as they arrive.** Point Fireberry at a [Hookdeck Inspect](https://inspect.hookdeck.com) URL to inspect and replay real deliveries, with no account or setup required. It's the quickest way to check that your body template renders the JSON you expect.

## Setting up Fireberry webhooks

Generate a long random secret first (`openssl rand -hex 32` works) and store it in your app's environment.

1. Create an automation: set the **Type**, the **When** (for example *Account is created*) and, if you need one, an **If** filter (for example *Status equals Lead*).
2. Under **Then**, click **+ Add Action** and choose **Webhook**.
3. Under **Request Method**, choose the method. `POST` is the usual choice.
4. Enter your HTTPS endpoint in **URL**.
5. Under **Header**, click **+ Add Header** and add `Content-Type` with `application/json`. Add a second header for your secret, for example `X-Webhook-Secret` with your secret value, or `Authorization` with `Bearer <secret>`.
6. Write the **Body**, using field references for record values.
7. Save and activate the automation, then trigger it with a test record.

Each send appears as a system log in the related record's stream, which is a quick way to confirm the automation ran.

For local development, use the [Hookdeck CLI](/docs/cli): `hookdeck listen 3000 fireberry --path /webhooks/fireberry` gives you a public HTTPS URL that forwards to your local server, plus a web UI for inspecting and replaying deliveries, with no account required. Use the generated URL in the action.

**With Hookdeck.** Create a Fireberry source in Hookdeck and enter the **Header Name** and **Header Value** exactly as they appear in the action, including any `Bearer ` prefix. The source pre-selects `POST` as the allowed method. If your action uses `GET`, `PUT`, `DELETE` or `PATCH`, allow that method on the source as well, since the source only accepts the methods you allow.

## Securing Fireberry webhooks

Authenticating a Fireberry request means comparing your secret header against the stored value. Look the header up case-insensitively, compare the whole value (any `Bearer ` prefix included) in constant time, and check lengths first because `crypto.timingSafeEqual` throws on buffers of different lengths. Accept every method your automations use, and allow for an empty body on `GET`.

```javascript
const crypto = require('crypto');
const express = require('express');

const app = express();

function safeEqual(a, b) {
  const x = Buffer.from(String(a), 'utf8');
  const y = Buffer.from(String(b), 'utf8');
  return x.length === y.length && crypto.timingSafeEqual(x, y);
}

function verifyFireberryRequest(headers) {
  const secret = process.env.FIREBERRY_WEBHOOK_SECRET;
  if (!secret) return false; // fail closed when unconfigured
  const name = (process.env.FIREBERRY_WEBHOOK_HEADER || 'X-Webhook-Secret').toLowerCase();
  const received = headers[name];
  return typeof received === 'string' && safeEqual(received, secret);
}

// The action can use any of five methods, so accept them all on this route.
app.all('/webhooks/fireberry', express.raw({ type: '*/*' }), (req, res) => {
  if (!['POST', 'GET', 'PUT', 'DELETE', 'PATCH'].includes(req.method)) {
    return res.sendStatus(405);
  }
  if (!verifyFireberryRequest(req.headers)) {
    return res.sendStatus(401);
  }

  let payload = null;
  if (Buffer.isBuffer(req.body) && req.body.length > 0) {
    try {
      payload = JSON.parse(req.body.toString('utf8'));
    } catch {
      return res.sendStatus(400);
    }
  }

  res.sendStatus(200);
  // Route on the event label you put in your own body template, e.g. payload.event
});

```

The same check in Python:

```python
import hmac
import os

def verify_fireberry_request(headers) -> bool:
    secret = os.environ.get("FIREBERRY_WEBHOOK_SECRET")
    if not secret:
        return False
    name = os.environ.get("FIREBERRY_WEBHOOK_HEADER", "X-Webhook-Secret")
    received = headers.get(name)  # case-insensitive in Starlette and Flask
    if not received:
        return False
    return hmac.compare_digest(received.encode("utf-8"), secret.encode("utf-8"))

```

A static header authenticates the sender, not the body. It can't detect a modified request, and there is no timestamp or signature to stop a captured request from being replayed. Use an HTTPS URL, keep the secret out of the body (where it would be logged with every payload), and rotate it by editing the action if it may have leaked.

> **Make Fireberry webhooks production-ready.** [Hookdeck Event Gateway](/event-gateway) checks your secret header on every request, stores each one durably, and keeps your automations out of Draft by answering Fireberry even while your own service is failing.

## Fireberry webhook limitations and pain points

### Failing endpoints switch the whole automation off

**The Problem:** When your endpoint keeps returning errors, Fireberry sets the automation to **Draft**. Every action in it stops, not just the webhook, so a broken receiver can also stop the emails or record updates in the same automation.

**Why It Happens:** Fireberry drafts an automation after 1,000 consecutive error responses within 24 hours, or five consecutive error responses over a period longer than 24 hours. It emails the automation's creator and your primary system user when this happens.

**Workarounds:**

* Keep the receiver simple and fast, and return `2xx` once the request is authenticated and stored.
* Put the webhook in its own automation if other actions must keep running when it fails.
* Watch for the Draft notification email and re-activate the automation once the cause is fixed.

**How Hookdeck Can Help:** Hookdeck answers Fireberry as soon as the request arrives and stores it, so errors in your own service never reach Fireberry's error count. Hookdeck then delivers to your service with [automatic retries](/docs/retries), and [Issues](/docs/issues) alert you when those deliveries fail.

### No signature and no standard payload

**The Problem:** Fireberry requests carry no signature and no Fireberry-defined fields. The receiver has no built-in way to know where a request came from or which automation sent it.

**Why It Happens:** The webhook action sends exactly the method, headers and body you configure.

**Workarounds:**

* Authenticate with a secret header compared in constant time.
* Include an event label and the record ID in every body template.
* Use a different secret per automation, or per environment, so you can rotate them independently.

**How Hookdeck Can Help:** Hookdeck's Fireberry source compares the header you name against the exact value you enter. A request without a matching header still gets a 200 response, but Hookdeck marks it as failed verification and creates no event, so it never reaches your destination. Every request is stored with its headers and body for inspection.

### Undocumented retries

**The Problem:** Fireberry documents what happens after many consecutive errors, but not whether it retries a single failed request, or how long it waits for a response.

**Why It Happens:** The webhook automation article covers the Draft rule only.

**Workarounds:**

* Assume a failed request may be lost and reconcile important records from the Fireberry API.
* Make handlers idempotent in case a request does arrive twice.

**How Hookdeck Can Help:** Hookdeck stores every request on arrival and lets you replay any of them, so a failure on your side doesn't depend on Fireberry's retry behaviour to recover.

## Best practices

### Put an event name and ID in every body

Fireberry won't tell you which automation fired. Write it into the template, along with the record ID, so one endpoint can route many automations and deduplicate on `event` plus record ID.

### Separate the webhook from critical actions

Because a drafted automation stops every action, keep a webhook that might fail away from emails or updates that must always run.

### Use HTTPS and a header, never a URL token

Fireberry recommends `https://`. Keep the secret in a header rather than the URL or the body, where it would end up in logs.

### Acknowledge fast and process asynchronously

Return `200` once the header checks out and the request is stored, then do the work in the background. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

### Make handlers idempotent

See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency) for patterns that make repeated deliveries harmless.

## Conclusion

Fireberry webhooks are requests you design inside an automation: you pick the method, headers and body, and Fireberry sends them unsigned whenever the automation runs. Add a secret header and compare it in constant time, put an event label and record ID in the body, and keep your endpoint healthy, because repeated errors put the whole automation into Draft.

[Hookdeck Event Gateway](/event-gateway) checks the header, stores every request and answers Fireberry straight away, so problems in your service turn into retries and alerts instead of a drafted automation.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Fireberry webhooks reliably in minutes.