# Guide to Pipedrive Webhooks: Features and Best Practices

Pipedrive webhooks notify your systems when CRM data changes: a deal is created, a person is updated, an activity is deleted. If you're syncing Pipedrive with another system or triggering automation off sales activity, webhooks are how you react without polling.

This guide covers how Pipedrive webhooks work, the `action.entity` event model, the security model (HTTP Basic Auth, not signatures), the retry and ban behavior, and the best practices for production.

## What are Pipedrive webhooks?

Pipedrive webhooks are HTTP POSTs delivered to a URL you register, each describing a change to a CRM entity. The payload carries `meta`, `data` (the current state), and `previous` (changed fields on a change, the last state on delete, `null` on create).

Pipedrive webhooks do not use HMAC signatures or any request signing. Security is HTTP Basic Authentication: you set a username and password when creating the webhook, and Pipedrive sends them in the `Authorization` header of every delivery for you to verify.

## Pipedrive webhook features

| Feature | Details |
| --- | --- |
| Configuration | `POST /v1/webhooks` (`event_action` + `event_object` + `version=2.0`) or dashboard |
| Security | HTTP Basic Auth (`http_auth_user` / `http_auth_password`); no signatures |
| Transport | HTTPS required (self-signed certs unsupported) |
| Event format | `action.entity` (e.g. `create.deal`, `change.person`) |
| Payload | `meta`, `data` (current), `previous` (changed/last/null) |
| Retries | 3s, 30s, 150s (max 4 attempts; any 2xx = success) |
| Ban system | Repeated first-attempt failures accrue bans (10 -> 30-min suspension) |
| Auto-delete | No successful delivery for 3 consecutive days deletes the webhook |
| SDK | Official Node SDK (`pipedrive`); no official Python SDK |

## Common events

Pipedrive events combine an action and an entity as `action.entity`:

| Event | Fires when |
| --- | --- |
| `create.deal` | A deal is created |
| `change.person` | A person is updated |
| `delete.activity` | An activity is deleted |
| `*.deal` | Any action on deals (wildcard action) |
| `change.*` | Any entity changes (wildcard entity) |

Actions are `create`, `change`, `delete`, and `*`; entities include `activity`, `deal`, `lead`, `note`, `organization`, `person`, `pipeline`, `product`, `stage`, and `user` (v2 added `lead`).

## Setting up Pipedrive webhooks

Create a webhook via `POST /v1/webhooks` with `event_action`, `event_object`, `version=2.0` (the default), and Basic Auth credentials, or configure one in the dashboard:

```bash
curl -X POST "https://api.pipedrive.com/v1/webhooks?api_token=$PIPEDRIVE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subscription_url": "https://user:password@your-app.example.com/webhook",
    "event_action": "create",
    "event_object": "deal",
    "version": "2.0",
    "http_auth_user": "your-user",
    "http_auth_password": "your-password"
  }'

```

The endpoint must be HTTPS with a valid certificate (self-signed is unsupported).

## Securing Pipedrive webhooks

There's no signature to verify. Instead, verify the HTTP Basic Auth credentials Pipedrive sends in the `Authorization` header of every delivery, the ones you set at creation.

```javascript
const crypto = require("crypto");

const EXPECTED_USER = process.env.PIPEDRIVE_WEBHOOK_USER;
const EXPECTED_PASS = process.env.PIPEDRIVE_WEBHOOK_PASS;

function safeEqual(a, b) {
  const x = Buffer.from(a || "");
  const y = Buffer.from(b || "");
  return x.length === y.length && crypto.timingSafeEqual(x, y);
}

function authorized(header) {
  if (!header || !header.startsWith("Basic ")) return false;
  const [user, pass] = Buffer.from(header.slice(6), "base64").toString().split(":");
  return safeEqual(user, EXPECTED_USER) && safeEqual(pass, EXPECTED_PASS);
}

app.post("/webhook", express.json(), (req, res) => {
  if (!authorized(req.headers["authorization"])) {
    return res.sendStatus(401);
  }

  res.sendStatus(200); // acknowledge fast
  processQueue.add(req.body); // process asynchronously
});

```

The same check in Python:

```python
import base64
import hmac
import os

EXPECTED_USER = os.environ["PIPEDRIVE_WEBHOOK_USER"]
EXPECTED_PASS = os.environ["PIPEDRIVE_WEBHOOK_PASS"]

def authorized(header: str) -> bool:
    if not header or not header.startswith("Basic "):
        return False
    user, _, pw = base64.b64decode(header[6:]).decode().partition(":")
    return hmac.compare_digest(user, EXPECTED_USER) and hmac.compare_digest(pw, EXPECTED_PASS)

```

Because credentials are all that stands between the internet and your endpoint, keep the URL and credentials secret and serve HTTPS.

## Pipedrive webhook limitations and pain points

### No signatures, only Basic Auth

The Problem: There's no HMAC or request signature. Authenticity rests entirely on the Basic Auth credentials, so anyone with the URL and credentials (or a misconfigured endpoint that skips the check) can post events.

Why It Happens: Pipedrive's design uses Basic Auth rather than payload signing.

Workarounds:

* Always verify the Basic Auth credentials, use strong random values, and serve HTTPS so they aren't sent in the clear.

How Hookdeck Can Help: Hookdeck gives you a dedicated ingestion URL and can enforce its own verification and filtering in front of your endpoint, adding a layer beyond Basic Auth.

### The ban system and 3-day auto-delete

The Problem: Repeated first-attempt failures accrue bans (10 failures leads to a 30-minute suspension), and no successful delivery for 3 consecutive days deletes the webhook entirely. A flaky endpoint gets throttled, then removed.

Why It Happens: Pipedrive protects itself from endpoints that consistently fail.

Workarounds:

* Acknowledge with a 2xx fast so first attempts succeed and avoid bans.
* Monitor webhook existence and recreate a deleted webhook; reconcile missed data via the API.

How Hookdeck Can Help: Hookdeck always accepts deliveries and absorbs downstream failures itself, so first attempts succeed and your webhook never accrues bans or gets auto-deleted.

### Small retry budget

The Problem: Retries are only 3s, 30s, 150s (max 4 attempts). A short outage past that window drops the event.

Why It Happens: Pipedrive's retry budget is small.

Workarounds:

* Acknowledge fast, and reconcile against the API for anything you can't afford to miss.

How Hookdeck Can Help: Hookdeck retries to your downstream on a schedule you control, so Pipedrive's 4-attempt limit isn't your only safety net.

### Duplicates and using `previous`

The Problem: Retries can duplicate events, and the `previous` object varies by action (changed fields on change, last state on delete, `null` on create). Handlers that ignore this misread state transitions.

Why It Happens: At-least-once delivery plus an action-dependent payload shape.

Workarounds:

* Dedupe on a `meta` identifier, and branch on the action to interpret `previous` correctly.

How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so retries don't double-process. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

## Best practices

### Verify the Basic Auth credentials

Check the `Authorization` header against the username/password you set, compare in constant time, and serve HTTPS with a valid certificate.

### Acknowledge fast to avoid bans and auto-delete

Return 2xx immediately and process off a queue so first attempts succeed and your webhook isn't suspended or deleted. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

### Dedupe and interpret `previous` by action

Dedupe on a `meta` identifier, and read `previous` according to whether the action is create, change, or delete.

### Reconcile against the API

Given the small retry budget and auto-delete, reconcile periodically so a dropped or deleted webhook doesn't leave you out of sync.

## Conclusion

Pipedrive webhooks deliver CRM changes as `action.entity` events, secured only by the HTTP Basic Auth credentials you set (no signatures). The details that matter are verifying those credentials, acknowledging fast to avoid the ban system and 3-day auto-delete, and reconciling against the API given the small retry budget.

[Hookdeck](https://hookdeck.com) adds verification and filtering beyond Basic Auth, keeps your webhook alive by absorbing downstream failures, deduplicates, and durably queues every event at the edge, so your app processes trustworthy, unique CRM events.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Pipedrive webhooks reliably in minutes.