Skip to main content
Peopledat Logo

API version 1

Build on one stable result contract.

Everything below is workspace-scoped, snake_case JSON, and authenticated with a one-time-revealed API key.

OpenAPI 3.1
On this page

Quickstart

Create a pd_test_… key in Dashboard → Developer, then send a reserved sandbox address. Test keys never call the verification provider or spend credits.

curl — deterministic test verification
curl https://peopledat.com/api/v1/verifications \
  -H "Authorization: Bearer pd_test_…" \
  -H "Idempotency-Key: quickstart-001" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","mode":"power"}'

Authentication

Send Authorization: Bearer pd_live_… or pd_test_…. Keys are bound to one workspace, have explicit scopes, can expire or be revoked, and are shown only once at creation. Never embed a secret API key in browser code.

Free workspaces can use test keys with both REST and MCP. A live key—and therefore live REST or MCP work—requires an active subscription or any settled PayGo purchase. Stored live keys resume when that entitlement returns.

Create separate keys for separate systems, grant only the scopes each one needs, lower its read/write limits when practical, and use expiry plus an optional daily credit cap. A workspace can keep up to 20 active, unexpired keys.

Idempotency

Every chargeable POST requires an Idempotency-Key. PeopleDat stores the request digest and resource outcome for 24 hours. An identical retry returns the original outcome; a changed payload returns 409. Concurrent retries create one resource and one charge.

Deterministic sandbox scenarios

deliverable@peopledat.testcatch-all@peopledat.testrole@peopledat.testdisposable@peopledat.testspam-trap@peopledat.testfull@peopledat.testinvalid@peopledat.testdisabled@peopledat.testunknown@peopledat.test

Use hyphenated labels exactly as shown. Sandbox results are stable, free, and isolated from provider capacity accounting.

VerificationResultV1

Status is one of deliverable, risky, undeliverable, unknown, or excluded. The advisory action is send, review, remove, retry, or skip. An unperformed check is null, never falsely presented as false.

200 single-verification response
{
  "data": {
    "id": "job_01…",
    "email": "[email protected]",
    "reference": "lead-42",
    "result": {
      "version": 1,
      "status": "risky",
      "policy_action": "review",
      "reason_code": "catch_all",
      "score": 62,
      "verification_mode": "power",
      "verified_at": "2026-08-27T18:42:00.000Z",
      "billed": true,
      "credits_used": 1,
      "checks": {
        "syntax_valid": true,
        "domain_accepts_mail": true,
        "smtp_connectable": true,
        "deliverable": null,
        "catch_all": true,
        "disposable": false,
        "role_account": false,
        "free_provider": false,
        "inbox_full": false,
        "disabled": false,
        "spam_trap": false,
        "mx_records": ["mx.example.com"]
      }
    }
  }
}

A single request may instead return 202 with { "data": { "id": "job_01…", "status": "processing" } }. Poll that job ID rather than submitting the address again.

Verification is a point-in-time technical signal. Policy actions are recommendations and do not guarantee delivery, consent, engagement, or inbox placement.

REST endpoints and scopes

PeopleDat REST API endpoints and required scopes
MethodPathPurposeScope
POST/verificationsVerify one address synchronouslyverifications:write
POST/jobsSubmit up to 50,000 recordsjobs:write
GET/jobs/{id}Read job status and countsjobs:read
GET/jobs/{id}/resultsPage through canonical resultsjobs:read
POST/jobs/{id}/cancelCancel work before provider executionjobs:write
POST/jobs/{id}/exportsCreate a CSV, XLSX, or TXT exportexports:write
GET/exports/{id}Read export statusexports:read
GET/exports/{id}/downloadResolve a secured downloadexports:read
GET/creditsRead pooled organization creditscredits:read
GET/usageRead privacy-safe workspace usageusage:read

All URLs are relative to https://peopledat.com/api/v1. Resource identifiers outside the key's workspace return 404.

verifications:write covers synchronous single checks. Job creation/cancellation and job reading are intentionally separate. Export creation and export reading are also separate. Balance and usage each have read-only scopes. API keys cannot create keys, register webhooks, or change workspace settings.

Submit, poll, page, and export a bulk job

Bulk work is asynchronous and durable. Submit it once, keep the returned ID, then poll state and page results. The database record is the source of truth; a worker wake-up can be recovered if Redis misses it.

1. Submit up to 50,000 records
curl https://peopledat.com/api/v1/jobs \
  -H "Authorization: Bearer pd_test_…" \
  -H "Idempotency-Key: august-cleanup-001" \
  -H "Content-Type: application/json" \
  -d '{
    "name":"August cleanup",
    "mode":"power",
    "records":[
      {"email":"[email protected]","reference":"crm-101"},
      {"email":"[email protected]","reference":"crm-102"}
    ]
  }'

202 accepted
{
  "data": {
    "id": "job_01…",
    "status": "pending"
  }
}

  1. 2. Poll state: GET /jobs/job_01… until completed, failed, or cancelled. Back off between reads, or use a signed webhook for the terminal event.
  2. 3. Page results: GET /jobs/job_01…/results?limit=500, then pass the opaque next_cursor until has_more is false.
  3. 4. Create an export: POST /jobs/job_01…/exports with a new idempotency key and { "format": "csv" }. Formats are csv, xlsx, txt_safe, and txt_all.
  4. 5. Resolve the download: poll GET /exports/export_01…, then call GET /exports/export_01…/download. An authorized request receives a 302 to a short-lived signed object-storage URL.

You may call POST /jobs/job_01…/cancel with an idempotency key only while the job is still pending and has not been committed to provider execution.

Errors and cursor pagination

Errors use one stable envelope. Save the response and X-Request-Id for diagnostics, but never log your Bearer key or submitted addresses.

Stable error envelope
{
  "error": {
    "code": "IDEMPOTENCY_CONFLICT",
    "message": "Idempotency key was already used with a different request",
    "request_id": "6e07…"
  }
}

Results use opaque cursor pagination. Pass the returned next_cursor as ?cursor=…; do not construct or decode cursors. A null cursor means the page is final.

Cursor-paged results
{
  "data": [/* canonical result rows */],
  "pagination": {
    "next_cursor": "eyJ…",
    "has_more": true
  }
}

GET /jobs/{id}/results accepts limit=1…500 (default 100) and an optional cursor up to 128 characters. GET /usage accepts days=1…90 (default 30).

400Invalid body/query or missing/invalid idempotency key.
401Missing, malformed, expired, or revoked API key.
403Scope denied or live entitlement suspended.
404Resource not found in this workspace.
409Idempotency conflict/in progress, or job cannot be cancelled.
413Bounded request body is too large.
429Key or workspace minute bucket is exhausted.
503A required result/replay is temporarily unavailable.

Rate limits

  • Writes are configurable from 1–60 per minute per key; the default and maximum are 60
  • Reads are configurable from 1–300 per minute per key; the default and maximum are 300
  • Bulk submissions also share a 10-per-minute workspace limit
  • Each bulk job is capped at 50,000 records and a 10 MB JSON body

Authenticated responses include X-Request-Id, RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset (UTC epoch seconds). Authentication failures still include a request ID but cannot report a key bucket.

REST and MCP use transactionally reserved PostgreSQL minute buckets. If that reservation cannot complete, the request fails closed before protected work runs.

Webhook verification

Register up to five active HTTPS endpoints per workspace. Supported events are job.completed, job.failed, export.completed, export.failed, and credits.low. Payloads contain identifiers and aggregates, never addresses or source columns.

Read the exact raw request body. Compute lowercase hex HMAC-SHA256 with your one-time signing secret over ${timestamp}.${rawBody}. Compare it in constant time with the value after v1= in PeopleDat-Signature; read the timestamp from PeopleDat-Timestamp and reject stale requests.

Retries occur immediately, then after 1 minute, 5 minutes, 30 minutes, 2 hours, and 12 hours. Endpoints must use HTTPS on port 443 and cannot redirect.

Follow the complete signature, deduplication, retry, and troubleshooting guide →

Hosted MCP endpoint

Connect a Streamable HTTP MCP client to https://peopledat.com/mcp and send the same Bearer API key used by REST. The endpoint is stateless and stays inside the same workspace boundary, scopes, rate limits, exclusions, credit ledger, idempotency records, and privacy-safe audit path.

PeopleDat MCP tools and billing behavior
ToolPurposeBilling
credit_balanceRead the pooled organization balanceFree
usageRead aggregate workspace usageFree
recent_jobsList recent workspace jobsFree
job_statusRead one job stateFree
job_resultsPage through canonical resultsFree
estimate_bulk_workEstimate bounded bulk workFree
verify_oneRun one canonical verificationUp to 1 credit
create_bulk_jobCreate an asynchronous job of up to 50,000 recordsUp to max_credits

Every billable tool requires both an idempotency_key and explicit max_credits. Live calls fail before provider work if that ceiling is too low. Test keys use the deterministic peopledat.test scenarios and consume no credits.

MCP does not provide a privileged data path: API keys cannot create other keys or change webhook settings, and tools never bypass the canonical verification orchestrator.

Follow the complete MCP client, scope, billing, and troubleshooting guide →

Privacy and retention

API request logs keep workspace, key, request, route-template, status, duration, aggregate counts, source, and billed units for 90 days. They do not keep request bodies, raw addresses, raw IPs, or credentials. Idempotency records last 24 hours; webhook delivery diagnostics last 30 days.

See the Privacy Policy and Terms for account, credential, source-data, and acceptable-use responsibilities.

Ready to try it?

Create a free workspace and test every canonical result without a provider call or a credit charge.

Create a test key