Skip to main content
All posts
Automation6 min read

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.

Two PingRoom avatars move a closed clay folio through a small brass gate while Pingo watches beside a shut ledger.

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 needBetter starting point
Deal details, history, owner, value, or next actionPipedrive
Deal updates for suitable Pipedrive usersPipedrive notification settings
Closed-deal posts for a team already working in SlackDealbot for Slack
One terse signal for a stable shared group outside those user listsPipedrive webhook → relay → PingRoom Room
Sales handoff, assignment, audit, or onboarding workflowCRM 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_USERNAME and PIPEDRIVE_BASIC_AUTH_PASSWORD;
  • PIPEDRIVE_COMPANY_ID;
  • PIPEDRIVE_WEBHOOK_ID;
  • PIPEDRIVE_COMPANY_HOST, such as example.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.status is the current value and must be won;
  • previous contains only changed fields, so it must contain status with the prior value open or lost.

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.

Two PingRoom avatars check one sealed event token in a queue tray while Pingo waits beside an identical retry held behind a wooden stop.

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:

  1. Move the deal from open to won; exactly one fixed Ping should be queued.
  2. Replay the same v2 body and event ID; no second queue job or Ping should appear.
  3. Change the body while keeping the event ID; the relay should reject the conflict.
  4. Edit a deal that was already won; no new won alert should be queued.
  5. Send another action, entity, company, host, webhook ID, or invalid Basic credential; the receiver should reject or ignore it as designed.
  6. Make queue persistence fail; the relay should not acknowledge the source event as accepted.
  7. Make PingRoom return a throttle or server error; the queued job should remain retryable.
  8. 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.

View all posts