Guide to People Data Labs Webhooks: Features and Best Practices
People Data Labs (PDL) webhooks tell you which person records changed in each PDL data release. Instead of re-enriching every contact on a schedule, you receive the IDs of the records that were updated for the kinds of change you care about, such as a job change or a new work email, and refresh only those.
This guide covers how PDL webhooks are registered, how to authenticate them with a shared key header, what each delivery contains, and the practices that keep you from losing a month of updates.
What are People Data Labs webhooks?
PDL webhooks are for "subscribing enterprise API and Data License customers" only. You don't create them in a dashboard: you give your PDL team three pieces of information and they register the webhook for you.
- Target URL, the HTTPS endpoint that receives the payloads.
- Headers, the headers PDL sends with each request. PDL's docs say that "at a minimum, this should contain a shared key for secure authorization for accepting webhook events".
- Filters, the kinds of update you want to hear about.
When a release updates records that match your filters, PDL sends an HTTP POST with a JSON array of the updated records' PDL IDs. PDL doesn't sign the request. The shared key header is the only thing that tells a real PDL delivery from a forged one, so make sure it is part of the registration.
People Data Labs webhook features
| Feature | Details |
|---|---|
| Availability | Enterprise API and Data License customers |
| Configuration | Registered by your PDL team |
| Target URL | HTTPS only |
| Method and format | POST, JSON |
| Body | An array of PDL IDs |
| Batch size | 1,000 IDs per request |
| Frequency | Once a month, around each data release |
| Event field | None |
| Authentication | The shared key header you ask PDL to send |
| Signature and timestamp | None |
| Retries | None. Ask your PDL team to resend the entire batch |
Filters and payloads
Each filter watches a set of person fields:
| Filter | Updates based on |
|---|---|
education | education |
job_change | job_company_id, job_title |
location | location_name, location_locality, location_metro, location_region, location_country, location_continent, location_street_address, location_address_line_2, location_postal_code, location_geo |
mobile_phone_number | mobile_phone |
personal_emails | personal_emails, recommended_ |
phone_number | mobile_phone, phone_numbers |
social_profile | LinkedIn, Facebook, Twitter and GitHub URLs, usernames and IDs |
work_email | work_email |
Several filters on one webhook are combined with a logical OR, and PDL warns that an ID can then arrive twice: with mobile_phone_number and personal_emails on one webhook, "a PDL ID will appear twice" if both change in the same release. PDL suggests that "it might be better to create one webhook per filter".
The body is just the IDs, with no event type and no record of which filter matched. This is PDL's example:
[
"9adnit66-hdZ5lkBbq-AOQ_0000",
"YraxDoP16jzyjfxtn-1XJQ_0000",
"6Wu6sKeyNfaLF3CVBgoysg_0000",
"MRXuwdbvx-poOxpPIPYO9A_0000",
"9R7GG5mBULdNjHWbQnRsJA_0000"
]
To find out what changed, look the IDs up through the PDL API. With one webhook per filter, give each its own target URL path, such as /webhooks/pdl/job_change, so the path tells you which filter fired.
Inspect People Data Labs webhooks as they arrive. Give your PDL team a Hookdeck Inspect URL to see a delivery's exact headers and body, with no account or setup required.
Setting up People Data Labs webhooks
Generate a long random value first, for example Bearer followed by the output of openssl rand -hex 32, and decide which header carries it. Authorization matches PDL's example.
- Contact your PDL team or Customer Success Manager to register a webhook.
- Give them your HTTPS target URL.
- Ask them to include your shared key header. PDL registers the webhook for you, so this is the step to check: without the header, requests arrive with nothing to authenticate.
- Choose your filters. Consider one webhook, and one target URL, per filter.
- Agree how you will ask for a resend if a delivery fails.
To route through Hookdeck, create a source with the People Data Labs type and give its URL to your PDL team as the target URL. Enter the header's name in API Key Header and its exact value, including any Bearer prefix, in API Key. The source accepts POST.
Securing People Data Labs webhooks
Read the header, case-insensitively, and compare its whole value with the one you registered, in constant time. Don't strip a Bearer prefix: compare exactly the value PDL was given.
const crypto = require('crypto');
const express = require('express');
const HEADER = (process.env.PEOPLE_DATA_LABS_WEBHOOK_HEADER || 'Authorization').toLowerCase();
const SECRET = process.env.PEOPLE_DATA_LABS_WEBHOOK_SECRET; // the exact, whole header value
function safeEqual(received, expected) {
const a = Buffer.from(received, 'utf8');
const b = Buffer.from(expected, 'utf8');
// timingSafeEqual throws on unequal lengths, so check first.
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
const app = express();
app.post('/webhooks/pdl/:filter', express.raw({ type: '*/*' }), async (req, res) => {
const received = req.get(HEADER);
if (!SECRET || typeof received !== 'string' || !safeEqual(received, SECRET)) {
return res.sendStatus(401);
}
let ids;
try {
ids = JSON.parse(req.body.toString('utf8'));
} catch {
return res.sendStatus(400);
}
if (!Array.isArray(ids)) return res.sendStatus(400);
// PDL won't retry, so store the batch durably before returning 200.
// await saveBatch(req.params.filter, ids);
res.sendStatus(200);
});
The same check in Python:
import hmac
import os
HEADER = os.environ.get("PEOPLE_DATA_LABS_WEBHOOK_HEADER", "Authorization")
SECRET = os.environ.get("PEOPLE_DATA_LABS_WEBHOOK_SECRET", "")
def verify_pdl_request(headers) -> bool:
if not SECRET:
return False # fail closed when unconfigured
received = headers.get(HEADER) # Starlette and Flask headers are case-insensitive
if not received:
return False
# Compare bytes: compare_digest raises TypeError on a non-ASCII str.
return hmac.compare_digest(received.encode("utf-8"), SECRET.encode("utf-8"))
A static header authenticates the sender, not the body. It can't detect a modified payload, and with no signed timestamp a captured request can be replayed and still pass. The impact is limited because the body only holds IDs you then look up yourself, but serve the endpoint over HTTPS, use a long random value, and ask your PDL team to change the header if it might have leaked.
Make People Data Labs webhooks production-ready. Hookdeck Event Gateway checks the shared key on every PDL delivery, stores each batch durably, and lets you replay it if your processing fails.
People Data Labs webhook limitations and pain points
No automatic resend
The Problem: A failed delivery can cost you a month of updates.
Why It Happens: PDL's docs say that "in the event of a failure (i.e. your server does not return a 200), we will not automatically resend". You have to ask your PDL team, and they resend the entire batch.
Workarounds:
- Keep the receiver simple: check the header, store the IDs, return
200. - Monitor for the expected monthly deliveries, and contact PDL quickly if one is missing.
- Make processing idempotent, since a resend repeats the whole batch.
How Hookdeck Can Help: Hookdeck accepts each batch as soon as it arrives and stores it, so PDL sees a 200 even if your service is down. Hookdeck then delivers it with retries you configure, and you can replay any batch yourself.
Registration depends on someone else
The Problem: The webhook is set up without your shared key, or with the wrong filters.
Why It Happens: PDL registers webhooks on your behalf. You can't see or edit the configuration yourself.
Workarounds:
- Put the header name and value, target URL and filters in writing when you ask.
- Send a test request through the whole path before the first release.
How Hookdeck Can Help: Hookdeck's People Data Labs source compares the header you name with the exact value you enter. Hookdeck answers PDL with a 200 either way, but a request with a missing or wrong value is recorded as failed verification and never reaches your destination, so a misconfigured registration shows up in the request log.
Duplicate IDs
The Problem: The same record is refreshed twice in one release.
Why It Happens: Filters on one webhook are ORed, so an ID that matches two filters is sent twice.
Workarounds:
- Use one webhook per filter, as PDL suggests.
- Deduplicate IDs per release before looking them up.
How Hookdeck Can Help: Hookdeck's deduplication can drop repeated requests, such as a resent batch, before they reach your service.
Large, bursty deliveries
The Problem: A large release arrives as many requests of 1,000 IDs, and the lookups behind them overload your service.
Why It Happens: A whole month of updates is delivered around the same time.
Workarounds:
- Queue the IDs and look them up in a worker at a pace your service and PDL plan can sustain.
How Hookdeck Can Help: Hookdeck can set a max delivery rate on your destination, so batches reach your service at a steady pace.
Best practices
Store before you acknowledge
PDL won't retry, so a 200 should mean the IDs are saved. Do the lookups afterwards.
Store the full header value
Keep the exact value, prefix included, as one string and compare it whole. Put the name and value in configuration, not code.
Route by URL
The body doesn't say which filter matched. Give each webhook its own path and use it to decide what to refresh.
Make processing idempotent
Resends repeat the whole batch, and IDs can repeat across filters. Key your work on the PDL ID and the release. See our guide to webhook idempotency.
Process asynchronously
Return 200 quickly and do the enrichment calls in a worker. See why to process webhooks asynchronously.
Conclusion
People Data Labs webhooks send the IDs of updated person records in batches of 1,000, once a month, authenticated only by the shared key header you ask PDL to register. Make sure that header is part of the registration, compare it whole in constant time, use one webhook per filter, and store every batch before you acknowledge it, because PDL won't send it again on its own.
Hookdeck Event Gateway sits in front of your receiver, checks the header, and keeps every batch until your service has processed it.
Get started with Hookdeck for free and handle People Data Labs webhooks reliably in minutes.