How to Send Pipedrive Won-Deal Alerts to a Shared Room
Verify one Pipedrive v2 deal transition and send fixed shared-phone copy without forwarding deal, contact, company, or value data.

To send one Pipedrive won-deal alert to a shared group of phones, create a Pipedrive v2 webhook for change.deal, protect the relay with HTTP Basic auth, accept only a real open or lost → won transition, then queue fixed copy for a private PingRoom Room.
Pipedrive remains the deal record. The Room receives no deal title, person, organization, value, currency, owner, note, stage, or CRM link.
This is a webhook recipe, not a native Pipedrive integration. The destination Room's owner needs PingRoom Pro. You also need permission to create a Pipedrive webhook, a public HTTPS relay, a durable queue, and server-side secret storage.
Use Pipedrive or Slack first when they fit
Pipedrive already has notifications for deal and contact updates. Appropriate Pipedrive users can keep the record, details, and next action in the CRM. For a team already working in Slack, Pipedrive's Dealbot for Slack can post closed-deal updates to a selected channel.
| What people need | Better starting point |
|---|---|
| Deal details, history, owner, value, or next action | Pipedrive |
| Deal updates for suitable Pipedrive users | Pipedrive notification settings |
| Closed-deal posts for a team already working in Slack | Dealbot for Slack |
| One terse signal for a stable shared group outside those user lists | Pipedrive webhook → relay → PingRoom Room |
| Sales handoff, assignment, audit, or onboarding workflow | CRM and the team's operations or task system |
PingRoom fits the fourth row. A won alert says only that the agreed CRM transition occurred. It does not assign the onboarding work, prove that payment arrived, or replace the record the team must open next.
Define one fixed signal
Use reviewed server-side copy:
Pipedrive deal won
One selected Pipedrive deal moved to won.
If the recipients would immediately need the customer name or amount, they need authorized Pipedrive access or a different workflow. A lock-screen Ping should not become a second CRM.
Create a private Room for the stable group that needs this signal. Under Settings → Connections → From another app, add an incoming webhook and store its complete URL as PINGROOM_WEBHOOK_URL in your relay's secret store. The incoming-webhook guide covers the Room side; the webhook reference carries the current fields, limits, cooldown, and error contract.
Create one Pipedrive v2 webhook
Pipedrive's current v2 guide lets a regular user create webhooks under their own permission level; an admin can manage webhooks for other users. Pipedrive limits each user to 40 webhooks.
In Pipedrive, open Settings → Tools and apps → Webhooks. Create a webhook with:
- event action:
change; - event object:
deal; - version:
2.0; - subscription URL: your public HTTPS relay, with no redirect;
- HTTP auth username and password: long, random values stored only in Pipedrive and your relay.
Store these values on the server:
PIPEDRIVE_BASIC_AUTH_USERNAMEandPIPEDRIVE_BASIC_AUTH_PASSWORD;PIPEDRIVE_COMPANY_ID;PIPEDRIVE_WEBHOOK_ID;PIPEDRIVE_COMPANY_HOST, such asexample.pipedrive.com;PINGROOM_WEBHOOK_URL.
Use a permission-level user who can see the intended deals. Pipedrive does not send webhook events for objects that user cannot access.
Verify before reading the CRM event
Pipedrive v2 supports HTTP Basic auth for the subscription URL. Compare the complete Authorization value in constant time before parsing the JSON body. Then require the exact company, host, webhook, version, action, and entity you configured.
The important transition boundary is in two places:
data.statusis the current value and must bewon;previouscontains only changed fields, so it must containstatuswith the prior valueopenorlost.
That second check prevents an unrelated edit to an already-won deal from creating another won alert.
import { createHash, timingSafeEqual } from "node:crypto"; function constantTimeEqual(left, right) { const a = Buffer.from(left ?? "", "utf8"); const b = Buffer.from(right ?? "", "utf8"); return a.length === b.length && timingSafeEqual(a, b); } function validBasicAuth(header, username, password) { const expected = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`; return constantTimeEqual(header, expected); } function selectedWonTransition(event, env) { const meta = event?.meta; const data = event?.data; const previous = event?.previous; return ( meta?.action === "change" && meta?.entity === "deal" && meta?.type === "general" && meta?.version === "2.0" && String(meta.company_id) === env.PIPEDRIVE_COMPANY_ID && String(meta.webhook_id) === env.PIPEDRIVE_WEBHOOK_ID && meta.host === env.PIPEDRIVE_COMPANY_HOST && String(data?.id) === String(meta.entity_id) && data?.status === "won" && previous !== null && typeof previous === "object" && Object.hasOwn(previous, "status") && ["open", "lost"].includes(previous.status) ); } function eventKey(companyId, eventId) { const digest = createHash("sha256") .update(`${companyId}:${eventId}`) .digest("hex"); return `pipedrive-won:${digest}`; }
The production receiver should also reject an empty or oversized body, require application/json, validate Pipedrive's UUID-shaped meta.id, and require the numeric deal identity in meta.entity_id to match data.id.
Queue identity, not CRM content
Pipedrive supplies one event ID as meta.id. Derive an opaque key from that ID and the configured company ID. Store a body digest beside it so an exact retry replays safely while changed content under the same event identity becomes a conflict.
The durable queue job needs only this:
const key = eventKey(env.PIPEDRIVE_COMPANY_ID, event.meta.id); const bodyDigest = createHash("sha256").update(rawBody).digest("hex"); await queue.enqueueOnce(key, bodyDigest, { eventKey: key, request: { action: null, title: "Pipedrive deal won", message: "One selected Pipedrive deal moved to won.", correlation_id: key, }, });
Do not put the Pipedrive payload in that job. Queue persistence should happen before the relay returns 2xx to Pipedrive. Pipedrive retries a failed or timed-out webhook after 3, 30, and 150 seconds; repeated receiver failures can also ban or remove the webhook. A durable enqueue is the boundary between accepting the source event and attempting the phone signal.

Pingo the Pigeon, PingRoom's fictional Chief Marketing Officer, appears beside the closed folio in these illustrations. He cannot inspect CRM records, access the private Room, declare a deal won, or send the Ping. The sales team owns the status change; deterministic relay code owns the filter.
Let one consumer send the fixed Ping
One queue consumer posts the reviewed body and reuses the same key for PingRoom idempotency:
const response = await fetch(env.PINGROOM_WEBHOOK_URL, { method: "POST", redirect: "manual", headers: { Accept: "application/json", "Content-Type": "application/json", "Idempotency-Key": job.eventKey, }, body: JSON.stringify(job.request), }); if (response.status !== 200 || (await response.json())?.success !== true) { throw new Error("retry queued Ping"); }
Retry PingRoom throttles, server errors, network failures, and incomplete outcomes from the queue. Reuse the same key and identical request body. A new key is a new Ping, not a repair for a failed attempt.
Rehearse the boundary with a disposable deal
Before enabling ordinary CRM traffic, use a test Room and a disposable deal with generic fields:
- Move the deal from
opentowon; exactly one fixed Ping should be queued. - Replay the same v2 body and event ID; no second queue job or Ping should appear.
- Change the body while keeping the event ID; the relay should reject the conflict.
- Edit a deal that was already
won; no new won alert should be queued. - Send another action, entity, company, host, webhook ID, or invalid Basic credential; the receiver should reject or ignore it as designed.
- Make queue persistence fail; the relay should not acknowledge the source event as accepted.
- Make PingRoom return a throttle or server error; the queued job should remain retryable.
- Lock a test phone and confirm the preview contains no deal, person, company, value, currency, owner, note, stage, or CRM link.
The companion relay for this article passed 51 deterministic assertions with Pipedrive v2-shaped fixtures, a Basic-authenticated receiver, an idempotent in-memory queue, and a local mock of PingRoom's documented webhook response. No live Pipedrive account, public relay, PingRoom Room, CRM data, or phone delivery was tested.
An accepted PingRoom response means the Ping was created and entered PingRoom's normal delivery path. It does not prove that a phone displayed it, that a person saw it, that onboarding began, or that the deal produced revenue. Notification permission, connectivity, Focus modes, Room settings, and operating-system behavior still matter.
If the shared-Room path is the right fit, create the private Room, deploy the relay with a durable queue, and move one disposable deal through the exact transition before connecting real work.
The workflow and CRM data in this guide are illustrative. The two editorial illustrations were created with AI using approved PingRoom character references and reviewed by the PingRoom team.
PingRoom
Short-form communication.


