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

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 age, 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, strict_match.

V2 adds four optional parameters:

ParameterTypeDefaultPurpose
emailstringSearch by email address. V1 has no email lookup.
include_fuzzy_matchingbooleanfalseForce fuzzy name matching on the first pass. When false, the API runs exact first and falls back to fuzzy automatically on a zero-result response — V1 has no equivalent.
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",
      "aliases": ["Johnny Smith"],
      "is_dead": false,
      "age": 40,
      "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"],
      "phones": [{ "number": "(212) 555-0198", "type": "mobile", "score": 92 }],
      "current_addresses": [...],
      "historic_addresses": [...],
      "owned_properties": [...],
      "emails": [{ "email": "john.smith@example.com", "score": 88 }],
      "relatives": [...],
      "result_metadata": {
        "details_url": "/v2/person/P1234567890",
        "phones":             { "displayed": 4, "additional": 3 },
        "emails":             { "displayed": 1, "additional": 0 },
        "historic_addresses": { "displayed": 5, "additional": 2 },
        "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 age)age: integer | nullNew on both Search and Details. Computed from date_of_birth; year-only DOB returns a year-based approximation, missing or unparseable DOB returns null.
(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 also sorts the response's top-level keys into a scan-friendly order (identity → employment scalars → match signals → arrays → relatives last); rely on key names, not position, when parsing.

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

V2 broadens name matching to phonetic variants, common nicknames, initials, and typos. Zero-result searches automatically fall back to fuzzy matching on the same request — V1 has no such fallback. Set include_fuzzy_matching=true explicitly to start with fuzzy matching on the first pass instead of falling back only on empty. 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 because the list is capped (phones: 4, emails: 3, historic addresses: 5, owned properties: 5). The full lists are always 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 returns ranked preview lists, not full lists. Person Search now caps each list per result (phones: 4, emails: 3, historic addresses: 5, owned properties: 5) and surfaces the overflow count in result_metadata.{list}.additional. Lists are sorted by confidence score so the most useful entries appear first. Person Details (details_url) continues to carry the full, uncapped lists for callers who need everything.

  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.

Related

On this page