Validate emails in Pipedrive

Check the email address of each Pipedrive person and save the result in custom person fields that you pick, so your filters and automations can use it. Two small pieces do the work, and you can use either or both:

  • A webhook relay checks a person within seconds when it is added, or when its primary address changes.
  • A clean-up command checks every person of a Pipedrive filter that has no result yet.

Both run in your own accounts with your own keys: the relay as a Cloudflare Worker, the command with Node. Nothing needs to be installed from the Pipedrive Marketplace.

Before you start

  • An API key. Create one on the API keys page with the permission "Validate addresses". To clean a filter of more than 50 persons, also turn on "Bulk lists". A daily credit cap limits what a busy webhook can spend.
  • Your Pipedrive API token. In Pipedrive: Settings → Personal preferences → API. The token acts as you, so the relay sees only the persons you can see. Keep it secret.
  • Your company domain, the address you open Pipedrive at: acme for https://acme.pipedrive.com.
  • Node 22.18 or later for the clean-up command, and a Cloudflare account for the relay.
  • The files, which are built from our tested code:
    • relay.js: the webhook relay, one Cloudflare Worker module;
    • clean.mjs: the clean-up command and the field setup, one Node module;
    • webhook.json: the webhook's settings, for Pipedrive's API.

Create the result fields

The result goes into three custom person fields:

FieldValue
Email statusone of the five result statuses: valid, invalid, catch_all, unknown or disposable
Email status reasonwhy, such as accepted or no_mailbox (optional)
Email checked atwhen the check ran, as an ISO 8601 date and time in UTC

Create them once with the command:

export PIPEDRIVE_API_TOKEN=…  PIPEDRIVE_DOMAIN=acme
node clean.mjs --setup

It creates whichever of the three fields are missing, as Text fields, and prints their keys. To use fields of your own instead, set PIPEDRIVE_STATUS_FIELD, PIPEDRIVE_CHECKED_AT_FIELD and, if you want it, PIPEDRIVE_REASON_FIELD to each field's name or key, for both pieces. They must be custom person fields of type Text or Large text.

Check new and changed persons

  1. Deploy the relay to your Cloudflare account and give it its secrets:

    npx wrangler deploy relay.js --name ev-pipedrive-relay --compatibility-date 2026-10-01 --var PIPEDRIVE_DOMAIN:acme
    npx wrangler secret put EV_API_KEY --name ev-pipedrive-relay
    npx wrangler secret put PIPEDRIVE_API_TOKEN --name ev-pipedrive-relay
    npx wrangler secret put WEBHOOK_USER --name ev-pipedrive-relay
    npx wrangler secret put WEBHOOK_PASSWORD --name ev-pipedrive-relay

    WEBHOOK_USER is any name, such as pipedrive. WEBHOOK_PASSWORD needs at least 32 random letters and digits, for example from openssl rand -hex 32. Your keys stay in the Worker's secret store. For EU data residency, add --var EV_REGION:eu to the deploy command.

  2. In Pipedrive, open Settings → Tools and apps → Webhooks → Create new webhook:

    • Event action * (or one webhook for create and one for change), event object person;
    • Endpoint URL the relay's address, such as https://ev-pipedrive-relay.<your-subdomain>.workers.dev/;
    • HTTP Auth the WEBHOOK_USER and WEBHOOK_PASSWORD you set on the relay.

    To create the webhook with Pipedrive's API instead, send webhook.json, with your values filled in, to POST /api/v1/webhooks.

  3. Add a test person with the address no_mailbox@sandbox.email-validation.org, a test address that costs nothing. Within a few seconds its Email status is invalid. Then delete the test person.

The relay checks a person when it is created, and when its primary address changes. It ignores every other change, including its own write to the result fields, so a result never starts a second check. Before it checks, it reads the person, so it always checks the address as it is now. A repeated delivery of an event it already checked is skipped, and the relay refuses any request without the webhook's credentials.

Clean a filter

Create a person filter in Pipedrive with the persons to check. Its id is the number at the end of the address while the filter is open, such as 12 in …/persons/list/filter/12.

export EV_API_KEY=…  PIPEDRIVE_API_TOKEN=…  PIPEDRIVE_DOMAIN=acme
node clean.mjs --filter 12 --dry-run    # counts what it would check
node clean.mjs --filter 12              # checks and writes the results

The command skips persons without an address and persons that already have a status other than unknown (add --revalidate to check them again). Up to 50 persons are checked one by one. More go into one bulk job: the command uploads the list, starts it, waits for it, and writes each result to its person.

If a run stops for any reason, such as no credits or a closed laptop, run the same command again. It keeps the bulk job's id in a small state file (ids only, no addresses) and resumes that job, so a list is never paid for twice. Exit code 75 means the job was still running when the command stopped waiting: run it again later.

Other options: --region eu for EU data residency, --status-field, --reason-field and --checked-at-field for your own fields, --rate for Pipedrive requests per second (default 8), and --wait-minutes for how long to wait for a bulk job (default 240).

Answers and retries

Pipedrive treats any answer other than 2xx as a failure: it delivers again up to three times, and it can pause or remove a webhook that keeps failing. So the relay answers with an error only when trying again can work.

The relay answersWhenWhat to do
200 savedThe person was checked and the result writtenNothing
200 ignored or skippedNo new address, the person is gone, or the event was already checkedNothing
200 not_checkedThe key was refused, there are no credits, the key reached its daily cap, or a result field is missingFix the cause, then clean the filter to catch up
200 not_savedThe check ran but Pipedrive did not take the resultClean the filter to catch up
503A rate limit or an outage before the checkNothing: Pipedrive delivers again
401Wrong or missing webhook credentialsCheck HTTP Auth on the webhook

Nothing is charged for a delivery that answers 503 or not_checked.

Costs and limits

  • Each checked person is one check. Results with the status unknown are free, and so are the test addresses.
  • The relay answers within Pipedrive's 10-second limit, so it gives a check at most 5 seconds.
  • Each read and write uses Pipedrive API tokens from your company's daily budget. The clean-up command spaces its requests to stay under Pipedrive's rate limits and waits when Pipedrive asks it to.
  • Our own rate limits apply to the relay as to any other client.

Updated · Maintained by the email-validation.org team