- Prosyo Docs
- Integrations
- Signed webhooks
On this page
Looking for the opposite direction, to start Prosyo outreach when something happens in another app? See Custom triggers.
Prosyo can POST a JSON event to any HTTPS URL when something happens. Use this to connect n8n, Zapier, 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.
- 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.
- In Prosyo, go to Integrations and click the Custom webhook card. Its details open in a panel on the right.
- Click Connect Custom webhook.
- Paste the URL into HTTPS endpoint and click Connect.
- Copy the Signing secret with Copy secret. It's shown once. You can rotate it later.
- Under Events, choose the events to send. All of them are ticked at first.
- Under Field mapping, choose which prospect fields appear in
data, and type the JSON key each one should use. - Click Save mapping.
- 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#
{
"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": "[email protected]",
"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
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
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
$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 (bydata.prospect_idor 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.
