# Retrieve a lead

`GET /v1/leads/{lead_id}`

Returns a lead's details and its pipeline card as it is on the board now.

**Scope:** `leads:read`

Details are read from where `POST` and `PATCH` store them. The card is the one the key's member may open: the lead's main (sales) card, or, for a member whose role limits the pipelines or assigned records they see and who may open only a follow-through card of the lead (for example an installer card on another team's pipeline), that card, with its own `id`, `pipeline_id`, `stage` and `assigned_member_id`. `deal_value` and `custom_fields` come from the deal it shares with the main card, the deal your `custom_fields` writes and file uploads go to. Nothing of a card the member may not open is returned.

The lead must belong to a campaign the key may reach and be one the key's member can see in DialEcho, otherwise `404`. Reading does not need the member's permission to manage leads.

The key sees the lead the way its member sees it in DialEcho. A contact field the member's role hides is `null`, and one it masks comes back masked (`***-***-0132`, `p***@example.com` or `Restricted`): `phone`, `email`, `first_name` and `last_name` (the name field), and `address`, `city`, `state` and `postal_code` (the address field). `company` is always shown. Roles without contact-field settings hide phone, email and custom fields; admins see every field.

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `lead_id` | `UUID` | Yes | The lead, as `POST /v1/leads` returned it. |

## Response

**Status:** `200 OK`

`notes` and `attribution` are not returned; the conversion report returns attribution.

| Name | Type | Description |
| --- | --- | --- |
| `id` | `UUID` | The lead. |
| `campaign_id` | `UUID` | The lead's campaign. |
| `phone` | `string \| null` | The phone number as stored: E.164 (`+14155550132`) for leads created through this API. `null` for a lead without a phone number. |
| `first_name` | `string \| null` | As stored; `null` when not set. |
| `last_name` | `string \| null` | As stored; `null` when not set. |
| `email` | `string \| null` | As stored; `null` when not set. |
| `address` | `string \| null` | As stored; `null` when not set. |
| `city` | `string \| null` | As stored; `null` when not set. |
| `state` | `string \| null` | As stored; `null` when not set. |
| `postal_code` | `string \| null` | As stored; `null` when not set. |
| `company` | `string \| null` | As stored; `null` when not set. |
| `card` | `object \| null` | The card the key's member may open, as described above; `null` only when the lead has no card the member can open. |
| `card.id` | `UUID` | The card (`pipeline_lead_id` in write responses). |
| `card.pipeline_id` | `UUID \| null` | The card's pipeline. |
| `card.stage` | `string \| null` | Slug of its current stage, as stage moves use it. |
| `card.deal_value` | `number \| null` | The deal value, shared with the main card, or `null`. |
| `card.assigned_member_id` | `UUID \| null` | The team member the card is assigned to, or `null`. |
| `card.custom_fields` | `object \| null` | The deal's custom field values (shared with the main card) by slug, as the text DialEcho stores. Empty fields, file and image fields and deleted fields are left out. `null` when the member's role hides custom fields; every value is `Restricted` when it masks them. |

## Example request

**curl**

```bash
curl "https://development.agencydevworks.ai/v1/leads/aaaaaaaa-0000-4000-8000-000000000001" \
  -H "Authorization: Bearer dei_your_key"
```

**JavaScript**

```js
const response = await fetch("https://development.agencydevworks.ai/v1/leads/aaaaaaaa-0000-4000-8000-000000000001", {
  headers: {
    "Authorization": "Bearer dei_your_key",
  },
});
const data = await response.json();
```

## Example response

**Status:** `200 OK`

```json
{
  "id": "aaaaaaaa-0000-4000-8000-000000000001",
  "campaign_id": "cccccccc-0000-4000-8000-000000000001",
  "phone": "+14155550132",
  "first_name": "Pat",
  "last_name": "Lee",
  "email": "pat@example.com",
  "address": "1 Market St",
  "city": "San Francisco",
  "state": "CA",
  "postal_code": "94105",
  "company": null,
  "card": {
    "id": "dddddddd-0000-4000-8000-000000000001",
    "pipeline_id": "eeeeeeee-0000-4000-8000-000000000001",
    "stage": "new",
    "deal_value": 12500.5,
    "assigned_member_id": "ffffffff-0000-4000-8000-000000000001",
    "custom_fields": { "roof_age": "12" }
  }
}
```

## Errors

| HTTP | Code | When |
| --- | --- | --- |
| 403 | `insufficient_scope` | The key does not have `leads:read`. |
| 404 | `not_found` | The lead does not exist or the key cannot reach it (other organization, a campaign outside the key, or a lead its member cannot see). |
| 422 | `invalid_request` | `lead_id` is not a UUID. |

Every endpoint can also answer `401 invalid_api_key`, `429 rate_limited` and `503 dependency_unavailable`. See [Errors](/api/#errors) in the overview.

## Related endpoints

- `PATCH /v1/leads/{lead_id}` · [Update a lead](/api/leads/update)
- `GET /v1/leads/{lead_id}/conversion` · [Retrieve a conversion](/api/reporting/get-conversion)
- `PUT /v1/leads/{lead_id}/stage` · [Move a lead's card](/api/leads/move-stage)
