New: pagination on person search, fuzzy matching, and more. See what's changed →
Whitepages

Person V1 → V2

Field mapping and behavior changes when moving from /v1/person to /v2/person.

This guide walks through every input and output change between the V1 and V2 person endpoints so you can migrate cleanly. V2 is a superset of V1: every V1 field has the same name and meaning in V2, with three shape changes called out below. The rest of V2's surface is purely additive — match scoring, fuzzy matching, pagination, per-result metadata.

TL;DR

  • Swap /v1/person for /v2/person in both your Search and Details calls.
  • Read results from response.results instead of the top-level array (Search only — Details is unchanged at the envelope level).
  • Update email reads from emails[i] (a string) to emails[i].email (an object with a confidence score).
  • Everything else just keeps working. Optional: start parsing match_score, matched_by, and result_metadata to take advantage of new V2 capabilities.

Endpoint URLs

OperationV1V2
SearchGET /v1/person/?...GET /v2/person/?...
DetailsGET /v1/person/{id}GET /v2/person/{id}

The Whitepages person ID format is unchanged (P prefix + 10 alphanumeric characters).

Request parameters

Every V1 search parameter works unchanged in V2 with the same name, type, and accepted values:

phone, name, first_name, middle_name, last_name, street, city, state_code, zipcode, radius, min_age, max_age, include_historical_locations.

V2 adds four optional parameters:

ParameterTypeDefaultPurpose
emailstringSearch by email address. V1 has no email lookup.
include_fuzzy_matchingbooleanfalseBroaden name matching to phonetic variants and common nicknames.
pageinteger1Page number, 1–10. Pages 2+ are billable per the billing policy.
page_sizeinteger15Results per page, 1–15.

GET /v2/person/{id} continues to take the person ID in the path with no additional parameters.

V1

A V1 Search response is a JSON array of up to 15 person records:

V1 /v1/person/ response
[
  {
    "id": "P1234567890",
    "name": "John Smith",
    "phones": [{ "number": "(212) 555-0198", "type": "mobile", "score": 92 }],
    "emails": ["john.smith@example.com"],
    "current_addresses": [...],
    "historic_addresses": [...],
    "owned_properties": [...],
    "relatives": [...],
    "aliases": ["Johnny Smith"],
    "is_dead": false,
    "date_of_birth": "1985-03-15",
    "linkedin_url": "https://linkedin.com/in/johnsmith",
    "company_name": "Acme Corp",
    "job_title": "Software Engineer"
  }
]

V2

A V2 Search response wraps the results in a results array and adds a top-level metadata block plus a per-result result_metadata block:

V2 /v2/person/ response
{
  "results": [
    {
      "id": "P1234567890",
      "name": "John Smith",
      "phones": [{ "number": "(212) 555-0198", "type": "mobile", "score": 92 }],
      "emails": [{ "email": "john.smith@example.com", "score": 88 }],
      "current_addresses": [...],
      "historic_addresses": [...],
      "owned_properties": [...],
      "relatives": [...],
      "aliases": ["Johnny Smith"],
      "is_dead": false,
      "date_of_birth": "1985-03-15",
      "linkedin_url": "https://linkedin.com/in/johnsmith",
      "company_name": "Acme Corp",
      "job_title": "Software Engineer",
      "match_score": 87,
      "matched_by": ["name", "address"],
      "result_metadata": {
        "details_url": "/v2/person/P1234567890",
        "phones":             { "displayed": 1, "additional": 0 },
        "emails":             { "displayed": 1, "additional": 0 },
        "historic_addresses": { "displayed": 1, "additional": 0 },
        "owned_properties":   { "displayed": 1, "additional": 0 }
      }
    }
  ],
  "metadata": {
    "result_count": 432,
    "page": 1,
    "page_size": 15
  }
}

Response shape (Details)

GET /v2/person/{id} returns a single record wrapped in result, matching the existing pattern for V2 detail endpoints:

V2 /v2/person/{id} response
{
  "result": {
    "id": "P1234567890",
    "name": "John Smith",
    "...": "...same fields as a Search result, minus result_metadata, match_score, matched_by"
  }
}

No result_metadata on Details

The result_metadata block is exclusive to Person Search. Person Details continues to return the full lists with no summary block.

Field-by-field mapping

Every V1 person-record field exists in V2 with the same name and meaning. Three shapes changed:

V1V2What changed
Top-level: [record, record, ...]Top-level: { "results": [...], "metadata": {...} }Search response is wrapped. Read response.results to get the V1-equivalent list. Pagination (metadata.result_count, .page, .page_size) and per-result result_metadata are additive.
emails: ["a@example.com", "b@example.com"]emails: [{ "email": "a@example.com", "score": 95 }, { "email": "b@example.com", "score": 60 }]Emails are now objects with a confidence score (0–100). Read .email to recover the V1 string. The list is sorted by score descending.
(no match_score)match_score: integer | null (1–99)New on Search only. Higher scores indicate stronger relevance + completeness.
(no matched_by)matched_by: list[string]New on Search only. Names the input field types that contributed to this result (e.g., ["phone"], ["name", "address"]).
(no result_metadata)result_metadata: {...}New on Search only. See result_metadata below.

All other fields — id, name, aliases, is_dead, phones[], current_addresses[], historic_addresses[], owned_properties[], relatives[], date_of_birth, linkedin_url, company_name, job_title — keep their V1 type, nullability, and semantics.

V2-only features

Pagination

V1 returned up to 15 results per call with no way to reach beyond them. V2 supports paging through up to 10 pages of 15 results each (150 total ceiling).

V2 paginated request
curl 'https://api.whitepages.com/v2/person?last_name=Smith&page=2&page_size=15' \
  --header 'X-Api-Key: YOUR_API_KEY'

response.metadata.result_count reports the total number of matching records, and metadata.page / metadata.page_size echo the page you fetched. See Pagination for details. Each page after the first is a separate billable request.

Match scoring

V2 results include a match_score (1–99) that ranks results by how closely they match your input across relevance and completeness, plus a matched_by array that names which input field types contributed. Use these to prioritize the most likely matches in your UI or pipeline.

{ "id": "P1234567890", "match_score": 87, "matched_by": ["name", "address"] }

Fuzzy / nickname matching

Set include_fuzzy_matching=true on Search to broaden name matching beyond exact spelling — phonetic variants, common nicknames, and typos. Useful when input names come from human entry (CRM notes, voicemail transcripts).

Confidence-scored emails

V2 emails are objects with a score (0–100) so you can prioritize the most likely-current address for outreach.

result_metadata on every Search result

Every Search result carries a result_metadata object summarizing each list and linking back to the canonical Person Details URL:

"result_metadata": {
  "details_url": "/v2/person/P1234567890",
  "phones":             { "displayed": 3, "additional": 0 },
  "emails":             { "displayed": 1, "additional": 0 },
  "historic_addresses": { "displayed": 4, "additional": 0 },
  "owned_properties":   { "displayed": 0, "additional": 0 }
}

displayed is the count of items in the corresponding list on this response; additional is the count linked to the person but not included. Today additional is always 0 — V2 Search still returns the full upstream lists. A future release will narrow each list to a small kept window; additional will then tell you how many more entries are available at details_url (GET /v2/person/{id}).

details_url is null for the rare result that arrives without a canonical Whitepages person ID (e.g., an unresolved phone-owner record). Those records are exempt from the upcoming list-narrowing — they are returned with their full lists regardless.

See the Changelog for the latest release notes on result_metadata behavior.

Behavioral differences

BehaviorV1V2
Result capHard cap at 15 per request, no pagination.Up to 10 pages × 15 results = 150 total.
Result orderingReturned in upstream Search-Layer order; no ranking signal.Sorted by match_score descending where applicable.
Email searchNot supported.New email query parameter.
Empty resultsEmpty array [] with HTTP 200.{ "results": [], "metadata": { "result_count": 0, ... } } with HTTP 200.
Phone scoringPhones include score (0–100). Unchanged.Same.
404 on DetailsBillable in V1.Same. (Note: V2 Property 404 on Details is not billable; Person Details 404 is still billable. See Billing.)

Forward compatibility notes

V2 is the long-term home for the person endpoints. Two upcoming changes are worth knowing about while you migrate:

  1. Search will behave more like search. Today a Person Search response carries every linked phone, email, historic address, and owned property for each matched record — useful data, but more than most Search use cases need to identify a match and decide whether to drill in. A future release tunes Search to a lean, ranked preview per list: the items most likely to inform the match-vs-traverse decision, in priority order. Payloads shrink, results are easier to scan, and Person Details (details_url) continues to carry the full lists for callers who want everything. result_metadata.{list}.additional is the forward-compatible signal — it goes from 0 today to a non-zero count when the tuning ships, telling you how many more items are available on Details. The change has a 30-day customer notice window before it ships; subscribe to the Changelog to get the heads-up.

  2. No new V2-only required fields. All current V2 fields preserve V1's nullability contracts. Future additive changes will follow the same pattern.

Call translation examples

Search by phone

V1:

curl 'https://api.whitepages.com/v1/person?phone=2125550198' \
  --header 'X-Api-Key: YOUR_API_KEY'

V2:

curl 'https://api.whitepages.com/v2/person?phone=2125550198' \
  --header 'X-Api-Key: YOUR_API_KEY'

The only required change is the URL path. The V2 response wraps results in { "results": [...], "metadata": {...} }.

Search by name and city, page 2

V1 had no pagination — your only option was a single tighter query. V2:

curl 'https://api.whitepages.com/v2/person?last_name=Smith&city=Seattle&state_code=WA&page=2' \
  --header 'X-Api-Key: YOUR_API_KEY'

Pull full details for a confirmed match

V1:

curl 'https://api.whitepages.com/v1/person/P1234567890' \
  --header 'X-Api-Key: YOUR_API_KEY'

V2:

curl 'https://api.whitepages.com/v2/person/P1234567890' \
  --header 'X-Api-Key: YOUR_API_KEY'

V2 Details responses are wrapped in { "result": {...} }. The fields inside are a superset of V1 (no removals, no nullability changes).

Code translation snippets

V1
const response = await fetch(
  `https://api.whitepages.com/v1/person?name=${name}`,
  {
    headers: { "X-Api-Key": API_KEY },
  },
);
const records = await response.json();
for (const person of records) {
  console.log(person.name, person.emails[0]);
}
V2
const response = await fetch(
  `https://api.whitepages.com/v2/person?name=${name}`,
  {
    headers: { "X-Api-Key": API_KEY },
  },
);
const { results, metadata } = await response.json();
for (const person of results) {
  console.log(
    person.name,
    person.emails[0]?.email,
    "match:",
    person.match_score,
  );
}
console.log(`Total matches across all pages: ${metadata.result_count}`);

Python (Details)

V1 and V2
import requests

# V1
r = requests.get(
    "https://api.whitepages.com/v1/person/P1234567890",
    headers={"X-Api-Key": API_KEY},
)
record = r.json()                 # V1 returns the record directly

# V2
r = requests.get(
    "https://api.whitepages.com/v2/person/P1234567890",
    headers={"X-Api-Key": API_KEY},
)
record = r.json()["result"]       # V2 wraps in {"result": ...}

Need help?

If you hit a field that doesn't map cleanly, or you'd like guidance on adopting match_score / result_metadata in your pipeline, reach out via support.

On this page