---
title: "Signatoro webhooks: get an event when a signature or a team changes"
url: https://signatoro.com/docs/install-signature/agent/webhooks
description: "Signatoro posts a signed event to your URL when a signature changes and when someone is invited to, joins or leaves your company. Events, payloads and how to check the signature."
published: 2026-11-03
updated: 2026-11-03
---

# Signatoro webhooks: get an event when a signature or a team changes

Signatoro posts a signed event to your URL when a signature changes and when someone is invited to, joins or leaves your company. Events, payloads and how to check the signature.

Signatoro posts an event to a URL you choose when something changes, so a CRM, a spreadsheet, an n8n or Zapier workflow or your own app can follow along without asking the [API](https://signatoro.com/docs/install-signature/agent) on a schedule. Add an endpoint on the [Connect page](https://signatoro.com/home/connect?tab=automations), under Automations, on every plan.

## Which events you get

An endpoint on your own account gets your signature's events. A company owner can also add an endpoint for the company, which gets every member's signature and the team's changes.

| Event | When |
| --- | --- |
| `signature.updated` | A signature changed: the person saved it (on Signatoro or through an AI assistant), the owner edited their details, or the owner changed the company brand (one event per member). |
| `member.invited` | The owner invited someone to the company. |
| `member.joined` | Someone accepted their invitation. |
| `member.removed` | An invitation was withdrawn (`"was": "invited"`), or a member left or was removed (`"was": "member"`). |
| `webhook.test` | You pressed "Send test". |

## What each event looks like

Every event is a JSON `POST` with the same envelope:

```json
{
  "id": "evt_6f1c2b0e9d7a4c1f8e3b5a2d4c6e8f0a",
  "type": "signature.updated",
  "created_at": "2026-11-03T10:00:00.000Z",
  "account_id": "the account the endpoint belongs to",
  "data": {
    "person": { "id": "...", "name": "Maya Okafor", "email": "maya@northwind.example" },
    "company_id": "...",
    "signature": {
      "html": "<table>...</table>",
      "text": "Maya Okafor\nHead of Sales, Northwind\n...",
      "fingerprint": "3f2a..."
    }
  }
}
```

`signature.html` and `signature.text` are the same signature the API and the MCP server return. `fingerprint` changes only when the signature does, so you can skip an event whose fingerprint you already have.

Member events carry `company_id` and `email`; `member.joined` and `member.removed` for a member also carry `person` with their `id` and `name`.

## Check that an event came from Signatoro

When you add an endpoint, Signatoro shows its signing secret once (`whsec_...`). Each event carries a `Signatoro-Signature` header:

```
Signatoro-Signature: t=1793700000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
```

`v1` is an HMAC-SHA256 of the timestamp, a dot and the raw request body, keyed with your secret. Check it before you trust the event, and refuse one whose timestamp is more than five minutes old. In Node:

```js
import { createHmac, timingSafeEqual } from 'node:crypto';

function fromSignatoro(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(',').map((part) => part.split('=')),
  );
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));

  if (age > 300) return false;

  const expected = createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest();
  const given = Buffer.from(parts.v1 ?? '', 'hex');

  return given.length === expected.length && timingSafeEqual(given, expected);
}
```

Use the body exactly as it arrived; parsing and re-serializing the JSON changes it.

## Delivery

- Answer with any `2xx` status within 10 seconds. Signatoro does not read the response body.
- A timeout, a network error, a `429` or a `5xx` is tried again after 2 and then 8 more seconds. Other `4xx` answers are not retried.
- Redirects are not followed: give the final URL.
- The URL must use `https` and a public address.
- Events can arrive more than once or out of order. Use `id` to drop repeats and `created_at` to order them.
- The Connect page shows the last delivery for each endpoint, and "Send test" sends a `webhook.test` event at once (one every 10 seconds).
- An account can have up to 5 endpoints.

## For agents

To react to a signature change, ask the person to add an endpoint on the Connect page (Automations tab) and keep the secret it shows. Check the `Signatoro-Signature` header on every event, and fetch the signature from the [API](https://signatoro.com/docs/install-signature/agent) at send time as before: `signature.updated` tells you it changed, the API stays the source for each email.
