---
title: "Get stored contact details"
method: GET
path: "/v1/people/{profile_id}/contacts"
tags: ["Contacts"]
---

# Get stored contact details

`GET /v1/people/{profile_id}/contacts`

## Request

- Base URL: `https://api.recruitmcp.com`
- URL: `https://api.recruitmcp.com/v1/people/{profile_id}/contacts`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://recruitmcp.com/oauth/authorize`, token URL `https://recruitmcp.com/oauth/token`, scopes: `sourcing:read`)
  - OAuth 2 (authorization code, authorization URL `https://recruitmcp.com/oauth/authorize`, token URL `https://recruitmcp.com/oauth/token`, scopes: `contacts:spend`)

Free. Only what an earlier lookup found. Each email includes type work or personal when the lookup provided it. best_email and best_phone are the stored pick. contacts:spend can read contacts it paid for. sourcing:read can read them too.

Scope: `sourcing:read`. A key with `contacts:spend` is also accepted.

## Path parameters

- `profile_id` string, required

## Headers

- `RecruitMCP-Version` '2026-10-13'
- `RecruitMCP-Customer` string

## Response `200`

Stored contact details.

- Contacts
  - `profile_id` string, required
  - `canonical_id` string: Search id for this person when both profile ids are known.
  - `contacts` object, required
    - `status` 'ready' | 'not_found' | 'pending' | 'expired', required
    - `emails` object[], required
      - `value` string
      - `type` 'personal' | 'work', nullable: work or personal when the lookup provides it. Null when it does not.
      - `line` 'mobile' | 'work_phone' | 'work' | 'personal': Provider line. mobile and work_phone stay on phones.
      - `confidence` number, nullable
      - `flagged` boolean: True when a plausibility check says this entry is clearly not this person.
      - `flag_reason` string: Short reason, at most 12 words. Present when flagged is true.
    - `phones` object[], required
      - `value` string
      - `type` 'personal' | 'work'
      - `line` 'mobile' | 'work_phone' | 'work' | 'personal': Provider line. mobile and work_phone stay on phones.
      - `confidence` number, nullable
      - `flagged` boolean: True when a plausibility check says this entry is clearly not this person.
      - `flag_reason` string: Short reason, at most 12 words. Present when flagged is true.
    - `best_email` object, nullable, required
      - `value` string, required
      - `type` 'personal' | 'work', nullable, required: work or personal when the lookup provides it. Null when it does not.
      - `line` 'mobile' | 'work_phone' | 'work' | 'personal': Provider line. mobile and work_phone stay on phones.
      - `confidence` number, nullable, required
      - `reason` 'only_candidate' | 'mobile' | 'highest_rating' | 'personal_preferred' | 'work_preferred' | 'matches_employer_domain' | 'llm_plausibility', required: Why this address or number was chosen. llm_plausibility means a flagged entry changed the pick.
    - `best_phone` object, nullable, required
      - `value` string, required
      - `type` 'personal' | 'work', nullable, required: work or personal when the lookup provides it. Null when it does not.
      - `line` 'mobile' | 'work_phone' | 'work' | 'personal': Provider line. mobile and work_phone stay on phones.
      - `confidence` number, nullable, required
      - `reason` 'only_candidate' | 'mobile' | 'highest_rating' | 'personal_preferred' | 'work_preferred' | 'matches_employer_domain' | 'llm_plausibility', required: Why this address or number was chosen. llm_plausibility means a flagged entry changed the pick.
    - `expires_at` string, date-time, nullable
  - `credits` number: Credits charged for this person on the lookup. 0 on a miss, a cache hit, a pending lookup, and when this response did not itself charge.
  - `cost` Cost
    - `credits` integer, required: Credits charged by this call. Whole credits. 0 on an idempotent replay, where the body also has replayed: true and the header Idempotent-Replayed: true.
    - `cached_items` integer: Items read from cache. On a replay, the value of the first response.
    - `live_items` integer: Items fetched live by this call. 0 on a replay.
    - `upstream_calls` integer: Index calls made by this call. 0 on a replay.

## Other responses

- `400`: `invalid_id` (do not retry): profile_id is not a valid person id. `invalid_request` (do not retry): A field is missing or has a value this endpoint does not accept. `unsupported_version` (do not retry): RecruitMCP-Version is not a supported version.
- `401`: `unauthorized` (do not retry): Missing bearer API key.
- `403`: `forbidden` (do not retry): This customer is disabled. `insufficient_scope` (do not retry): This key does not include the scope this endpoint requires.
- `404`: `not_found` (do not retry): No contacts are stored for this profile.
- `429`: `rate_limited` (retry): Per-key rate limit exceeded.
- `503`: `contacts_unavailable` (do not retry): Contact lookup is not available on this server. Nothing was looked up and nothing was charged.

## Changes

- **2026-10-20** `ad27b35513a6`: 6 warning, 2 info
  - added the new `approval_forced` enum value to the `error/code` response property for the response status `400`
  - added the new `approval_forced` enum value to the `error/code` response property for the response status `401`
  - added the new `approval_forced` enum value to the `error/code` response property for the response status `403`
  - added the new `approval_forced` enum value to the `error/code` response property for the response status `404`
  - …4 more

[Operation history](https://skmtc.dev/recruitmcp/apis/recruitmcp-api/changes/v1/people/:profile_id/contacts/get.md)

---

[API](https://skmtc.dev/recruitmcp/apis/recruitmcp-api.md) · [All operations](https://skmtc.dev/recruitmcp/apis/recruitmcp-api/llms.txt) · [OpenAPI document](https://skmtc.dev/recruitmcp/apis/recruitmcp-api/revisions/ad27b35513a6?raw)
