---
title: "Signed Webhooks for LinkedIn Outreach Events | Prosyo"
description: "Send HMAC-signed JSON events from Prosyo to any HTTPS endpoint when prospects are created, stages change or replies arrive. Code samples included."
url: "https://prosyo.com/docs/integrations/webhooks/"
image: "https://prosyo.com/wp-content/uploads/2026/10/Prosyo-wordmark-white-vector.svg"
language: "de"
---

# Signed Webhooks for LinkedIn Outreach Events | Prosyo

Last updated November 6, 2026 4 min read

**On this page**

- Events
- Set up
- Payload
- Headers
- Verify the signature
- Responses and retries
- Rotate the secret

> Looking for the opposite direction, to start Prosyo outreach when something happens in another app? See [Custom triggers](https://prosyo.com/de/docs/integrations/custom-triggers/).

Prosyo can **POST a JSON event** to any HTTPS URL when something happens. Use this to connect [n8n](https://prosyo.com/de/docs/integrations/n8n/), [Zapier](https://prosyo.com/de/docs/integrations/zapier/), [Make](https://prosyo.com/de/docs/integrations/make/), a data warehouse or your own backend.

## Events#

| Event | Fires when |
| --- | --- |
| `prospect.created` | A prospect is added by import, LinkedIn search, the Chrome extension or by hand |
| `prospect.stage_changed` | A prospect moves stage in the table, board, side panel or Inbox |
| `prospect.enriched` | AI research or a first-touch line is saved |
| `conversation.reply_received` | A LinkedIn or email reply stops the sequence |
| `campaign.launched` | A campaign starts sending |
| `campaign.paused` | A running campaign is paused |
| `account.needs_reconnect` | A LinkedIn or email account needs reconnecting |
| `intent.high_intent` | Someone unlocked in Intent who fits your ideal customer shows strong buying signals |
| `intent.playbook_matched` | An Intent playbook picks up a person. Sent only for playbooks with **Send each match to Slack, HubSpot or your webhook when those are connected** turned on. |

## Set up#

You need to be a workspace **owner or admin**.

1. Create an endpoint that accepts **POST** with a JSON body. It must be **HTTPS** on the standard port (443) and publicly reachable. HTTP, other ports, private and internal addresses, and URLs with a username or password are blocked.
2. In Prosyo, go to **Integrations** and click the **Custom webhook** card. Its details open in a panel on the right.
3. Click **Connect Custom webhook**.
4. Paste the URL into **HTTPS endpoint** and click **Connect**.
5. Copy the **Signing secret** with **Copy secret**. It's shown once. You can rotate it later.
6. Under **Events**, choose the events to send. All of them are ticked at first.
7. Under **Field mapping**, choose which prospect fields appear in `data`, and type the JSON key each one should use.
8. Click **Save mapping**.
9. Click **Test connection** to send a sample.

The test event has the type `integration.test` and uses a sample person, not one of your prospects.

## Payload#

JSON

```json
{
  "id": "evt_01HQEXAMPLE",
  "type": "conversation.reply_received",
  "created_at": "2026-08-17T12:00:00.000Z",
  "workspace_id": "ws_…",
  "data": {
    "prospect_id": "pr_…",
    "campaign_id": "cp_…",
    "event": "conversation.reply_received",
    "email": "alex@acme.com",
    "full_name": "Alex Rivera",
    "title": "Head of Sales",
    "company": "Acme",
    "linkedin_url": "https://www.linkedin.com/in/alexrivera",
    "stage": "replied",
    "personalized_message": "…"
  }
}
```

`data` always has `prospect_id`, `campaign_id` and `event`. The other fields inside `data` follow your field mapping. The panel also shows a **Sample event payload** you can copy with **Copy JSON**. It's only an example: live events contain the fields in your mapping plus `prospect_id`, `campaign_id` and `event`.

## Headers#

| Header | Value |
| --- | --- |
| `Content-Type` | `application/json` |
| `X-Prosyo-Signature` | Hex HMAC-SHA256 of the raw body, using your signing secret |
| `X-Prosyo-Event` | The event type, for example `conversation.reply_received` |
| `X-Prosyo-Delivery-Id` | The ID of this delivery, the same as `id` in the body |
| `User-Agent` | `Prosyo-Webhooks/1.0` |

## Verify the signature#

Compute HMAC-SHA256 of the **raw request body** with your signing secret, as lowercase hex, and compare it to `X-Prosyo-Signature`. Reject the request if they don't match.

**Node.js**

JavaScript

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

function isValidProsyoRequest(rawBody, signatureHeader, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
```

**Python**

Python

```python
import hmac, hashlib

def is_valid_prosyo_request(raw_body: bytes, signature_header: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature_header or "")
```

**PHP**

PHP

```php
$expected = hash_hmac('sha256', file_get_contents('php://input'), $secret);
$valid = hash_equals($expected, $_SERVER['HTTP_X_PROSYO_SIGNATURE'] ?? '');
```

Always sign the **raw** body. Parsing the JSON and re-encoding it changes the bytes, and the signature won't match.

## Responses and retries#

- Return any **2xx** status within **10 seconds** to mark the delivery successful. Reply first and do slow work afterwards.
- Failed deliveries are **retried** with growing gaps for about eight hours.
- Once your endpoint is fixed, click **Test connection** (or wait for the next event). When a delivery succeeds again, Prosyo resends the deliveries that ran out of retries in the last 30 days. Each one carries the prospect's details as they are at that moment.
- While deliveries fail, the card shows **Needs attention**. **Recent deliveries** in the panel lists the latest deliveries, and **Last delivery error** shows the reason.
- Every attempt is a new delivery with a new `X-Prosyo-Delivery-Id`, so the same event can reach you more than once. Make your workflow safe to run twice, for example by looking the person up in your own system (by `data.prospect_id` or email) and updating the record if it's already there, instead of always creating a new one.

## Rotate the secret#

Open the **Custom webhook** card and click **Rotate secret**. The old secret stops working straight away, so copy the new one and update it in your workflow. Deliveries signed with the new secret fail verification until you do.

Connect it in Prosyo

Open Integrations in the app to set this up in a few minutes.

[Connect in Prosyo](https://app.prosyo.com/integrations)

## Related guides

[Custom triggers Turn any form, CRM, Stripe or Calendly event into LinkedIn outreach: add the lead and enroll them in a Prosyo campaign with n8n, Zapier, Make or code.](https://prosyo.com/de/docs/integrations/custom-triggers/) [API reference Prosyo REST API reference: authentication, add leads, enroll in campaigns, enrichment, bulk actions, prospects, inbox, Intent signals, limits and errors.](https://prosyo.com/de/docs/integrations/api-reference/) [n8n Trigger n8n workflows from Prosyo events, verify webhook signatures, and add leads and enroll them in LinkedIn campaigns from n8n.](https://prosyo.com/de/docs/integrations/n8n/) [Zapier Use the Prosyo Zapier app: start Zaps on new prospects, stage changes and replies, and create prospects, update stages or add people to lists from other apps.](https://prosyo.com/de/docs/integrations/zapier/)
