<!-- @generated by `npm run docs:gen` from src/content/docs/ — DO NOT EDIT. -->

# Email and phone

Get a person's business email addresses or phone numbers by profile id — Verified email and Verified phone number. You pay only when we hold one.

`GET /v1/profiles/{id}/email`

`GET /v1/profiles/{id}/phone`

Authenticated with your `x-api-key`. See [Authentication](https://ask.xverum.com/docs/authentication.md).

## How it works

Pass a profile `id` — the same id a [search](https://ask.xverum.com/docs/search.md) result carries — to get that person's **Verified email** (`/email`: every business email address we hold) or **Verified phone number** (`/phone`: up to 3 numbers, best first).

**You pay only when we hold one.** A person we hold nothing for returns a `200` with `has_email: false` / `has_phone: false` and is charged **`0`**. Read `has_email` / `has_phone` first: `false` is a complete answer, not a failure, and retrying it will not change the result. A `404 profile_not_found` means no such profile — a different thing from a profile with no email or phone.

Only business addresses are returned — personal mailboxes (Gmail, Outlook and the like) are not. A phone number is returned only when its country is known from the number itself or from the person's location.

## Request

```http
GET /v1/profiles/{id}/email
Host: search-api.xverum.com
x-api-key: XVERUM-API-KEY
```

### Path parameter

| Parameter | Description |
| --- | --- |
| `id` | Opaque profile id, e.g. from a search result's `id` |

## Example

```bash
curl "https://search-api.xverum.com/v1/profiles/a1b2c3d4/email" \
  -H "x-api-key: XVERUM-API-KEY"
```

```bash
curl "https://search-api.xverum.com/v1/profiles/a1b2c3d4/phone" \
  -H "x-api-key: XVERUM-API-KEY"
```

## Response — email

| Field | Type | Description |
| --- | --- | --- |
| `has_email` | boolean | Whether we hold a business email for this person. **Check this first.** |
| `emails` | object[] | Every address we hold; `[]` when `has_email` is `false` |
| `emails[].email` | string | The address, lowercased |
| `emails[].confidence` | string \| null | The source's confidence in the address, e.g. `High`; `null` if none |
| `emails[].last_checked` | string \| null | When the address was last checked (`YYYY-MM-DD`); `null` if unknown |
| `credits_used` | integer | Credits deducted — `2` when an email is held, `0` when it is not |
| `credits_remaining` | integer | Balance left after this call |
| `request_id` | string | Correlation id — also returned in the `X-Request-Id` header |

```json
{
  "has_email": true,
  "emails": [
    { "email": "jane.doe@example.com", "confidence": "High", "last_checked": "2026-09-01" }
  ],
  "credits_used": 2,
  "credits_remaining": 4998,
  "request_id": "1a2b3c4d5e6f7081"
}
```

## Response — phone

| Field | Type | Description |
| --- | --- | --- |
| `has_phone` | boolean | Whether we hold a phone for this person. **Check this first.** |
| `phones` | object[] | Up to 3 numbers, best first; `[]` when `has_phone` is `false` |
| `phones[].phone` | string | The number in international (E.164) form |
| `phones[].extension` | string | The extension; `""` when there is none |
| `phones[].line_type` | string \| null | `mobile`, `fixed_line` and so on; `null` if unknown |
| `phones[].country` | string \| null | The number's country (ISO 3166-1 alpha-2); `null` if non-geographic |
| `phones[].country_source` | string | How `country` was decided: `number` (from the number's own country code) or `person_country` (from the person's location) |
| `credits_used` | integer | Credits deducted — `6` when a phone is held, `0` when it is not |
| `credits_remaining` | integer | Balance left after this call |
| `request_id` | string | Correlation id — also returned in the `X-Request-Id` header |

```json
{
  "has_phone": true,
  "phones": [
    {
      "phone": "+12025550123",
      "extension": "",
      "line_type": "mobile",
      "country": "US",
      "country_source": "number"
    }
  ],
  "credits_used": 6,
  "credits_remaining": 4994,
  "request_id": "1a2b3c4d5e6f7081"
}
```

### Example responses — nothing held

```json
{
  "has_email": false,
  "emails": [],
  "credits_used": 0,
  "credits_remaining": 5000,
  "request_id": "1a2b3c4d5e6f7081"
}
```

```json
{
  "has_phone": false,
  "phones": [],
  "credits_used": 0,
  "credits_remaining": 5000,
  "request_id": "1a2b3c4d5e6f7081"
}
```

## Billing

A delivered email costs **2 credits** and a delivered phone **6 credits** — per person, however many addresses or numbers they have — echoed as `credits_used`. When nothing is held the call is **free**. Each charge is deduped per `(api-key, id)` within a short window, separately for email and phone: buying a person's email never makes their phone free.

Two identical calls sent at the same moment are billed once: the second is answered `409 request_in_progress` with a `Retry-After` header — wait and retry, and the repeat is free.

## Errors

All `/v1` errors use the structured envelope (see [Authentication](https://ask.xverum.com/docs/authentication.md)):

| Status | `error.code` | Condition |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing or invalid API key |
| `402` | `out_of_credits` | Out of credits — the envelope carries an `upgrade_url` to top up |
| `403` | `account_not_authorized` | Account not authorized |
| `404` | `profile_not_found` | No profile exists for the given `id` |
| `409` | `request_in_progress` | An identical call is still in flight — retry after `Retry-After` |
| `422` | `validation_error` | The `id` is empty or longer than 128 characters |
| `429` | `rate_limited` | Rate limit exceeded — see [Rate limits](https://ask.xverum.com/docs/rate-limits.md) |
| `502` | `upstream_unavailable` | The contact store failed — nothing charged, retry shortly |
| `503` | `search_unavailable` | Temporarily unavailable — retry shortly |
