> Featurevote docs. Every page, as an index: https://featurevote.app/llms.txt

# Webhooks

Send new requests, comments and messages to Make, n8n, Zapier or your own server

Source: https://featurevote.app/docs/integrations/webhooks
Last updated: 2026-10-10

A webhook sends what happens on your board to another tool the moment it happens. Use it to add every new request as a row in a spreadsheet, post it to a channel, or create a card in the tool you plan your work in, without writing code.

It works with any tool that can receive a webhook, such as Make, n8n, Zapier (on its paid plans) or your own server.

## Set Up

1. In your other tool, create a webhook trigger and copy the link it gives you. It starts with `https://`.
2. In FeatureVote, go to **Settings → Integrations** and find **Webhooks**.
3. Paste the link, tick the events you want and click **Save webhook**.
4. Pick an event next to **Send test** and click it. Your tool receives an example message, which it uses to learn the fields. Send one test for each event you use.

The card then shows the last delivery, for example *Last sent Oct 10, 2026, 10:40 AM UTC · 200*.

## Recipes

### Make: add each new request to Google Sheets

1. Create a scenario that starts with **Webhooks → Custom webhook**, and copy its address.
2. Save it in FeatureVote with **New request** ticked, then click **Send test**.
3. In Make, click **Redetermine data structure** if it asks, and add **Google Sheets → Add a row**.
4. Map columns to `data.request.title`, `data.request.url`, `data.request.author.email` and anything else you need.

### n8n

Start a workflow with the **Webhook** node, set its method to `POST`, and use its production URL. Send a test from FeatureVote while the node is listening to see the fields.

### Zapier

Use **Webhooks by Zapier → Catch Hook** as the trigger and paste its link. Webhooks by Zapier is part of Zapier's paid plans.

### Your own server

Accept a `POST` with a JSON body, answer with any `2xx` status within 10 seconds, and verify the signature (see below).

Changes made through an AI client (MCP) are not sent as webhook events yet.

## Events

| Event | Sent when |
| --- | --- |
| `request.created` | Someone posts a request on the board or in Discord, you add one in FeatureVote, or you turn a message into one. Requests waiting for your approval are sent too, with status `pending_approval`. |
| `comment.created` | A visitor or your team comments on a request in FeatureVote. |
| `request.vote_milestone` | A request reaches 5, 10, 25, 50 or 100 votes. |
| `request.shipped` | You mark a request done and choose to tell its voters. |
| `message.received` | Someone sends your team a private message from the board. |

## The Message

Every message has the same envelope. Request events carry the same `request` object, so fields you map once work for the others.

```json
{
  "id": "msg_2f1c3a3e-5d7b-4f0e-9a43-6c1d1c0b9e5a",
  "type": "request.created",
  "timestamp": "2026-10-10T10:40:00.000Z",
  "data": {
    "board": {
      "name": "Acme",
      "url": "https://featurevote.app/boards/acme/board/main"
    },
    "request": {
      "id": "6f0e1d2c-3b4a-4c5d-8e9f-0a1b2c3d4e5f",
      "title": "Export to CSV",
      "description": "A button that downloads every request as a spreadsheet.",
      "status": "requested",
      "votes": 1,
      "private": false,
      "url": "https://featurevote.app/boards/acme/board/main?feature=6f0e1d2c-3b4a-4c5d-8e9f-0a1b2c3d4e5f",
      "author": { "name": "Ada Lovelace", "email": "ada@example.com" }
    }
  }
}
```

The other events add to `data`:

- `comment.created` adds `comment`, with `id`, `text`, `internal` and `author`.
- `request.vote_milestone` adds `milestone`, the vote count reached.
- `message.received` has `message` (with `id`, `text` and `author`) in place of `request`.

`votes` counts people, not weighted votes. `author.name` and `author.email` are `null` when the person did not give them. Text fields are cut at 5,000 characters.

Messages include the names and email addresses people gave you, so only send them to a tool you trust with that.

## Verifying the Signature

Messages are signed the [Standard Webhooks](https://www.standardwebhooks.com) way, so you can verify them with one of its libraries. Each request carries three headers:

- `webhook-id`, the same as the message `id`. Use it to skip a message you have already handled.
- `webhook-timestamp`, in seconds.
- `webhook-signature`, in the form `v1,<signature>`.

Copy your signing secret with **Copy signing secret** on the card. To check a message by hand in Node:

```js
import crypto from 'node:crypto';

function isFromFeatureVote(secret, headers, rawBody) {
  const key = Buffer.from(secret.replace('whsec_', ''), 'base64');
  const signed = `${headers['webhook-id']}.${headers['webhook-timestamp']}.${rawBody}`;
  const expected = crypto.createHmac('sha256', key).update(signed).digest('base64');

  return headers['webhook-signature'] === `v1,${expected}`;
}
```

Removing the webhook and adding it again gives it a new secret.

## Delivery

- Each event is sent once. A message that fails is not sent again, and the card shows why it failed.
- Your tool has 10 seconds to answer. Redirects are not followed.
- The link must be a public `https://` address.

Have a tool you'd like us to connect to directly? [Request it on our feature board.](https://ideas.featurevote.app/)
