---
title: "Retrieve a lead"
url: https://docs.light-ai.app/api-reference/leads/get-lead.md
canonical_url: https://docs.light-ai.app/api-reference/leads/get-lead
last_updated: 2026-10-13
summary: "GET /v1/leads/{lead_id}: Retrieve a lead"
api_status: beta
related:
  - https://docs.light-ai.app/api-reference/leads
---

# Retrieve a lead

> GET /v1/leads/{lead_id}: Retrieve a lead

`GET /v1/leads/{lead_id}`

|   |   |
| --- | --- |
| Scope | `leads:read` |
| Credential | API key: `Authorization: Bearer lai_live_…` (or `lai_test_…`). Partner keys add `Light-AI-Organization`. |
| Test mode | Works with test keys against simulated test objects. |

## Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `lead_id` | string | yes | The lead id (`lead_…`). Id prefix `lead_`. |

## Headers

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `Light-AI-Organization` | string |  | Partner keys: the connected organization to act for (`org_…`). Organization keys may omit it. Id prefix `org_`. |
| `Light-AI-Version` | string |  | Pin a dated API version (defaults to the key's version). One of: `2026-11-01`. |

## Response 200

The lead.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Id prefix `lead_`. |
| `object` | string | yes | Always `lead`. |
| `livemode` | boolean | yes | false for objects created with a test key. |
| `status` | string | yes | One of: `new`, `converted`, `spam`, `archived`, `duplicate`. |
| `held` | boolean | yes | Accepted while the organization was paused; converts automatically on resume. |
| `needs_address` | boolean | yes | A lead without a street address (none, or only a ZIP, city or region) waits for one (PATCH /v1/leads/{id} with address). |
| `source` | string | yes | One of: `website_widget`, `api`, `google_ads_lead_form`, `google_lsa`, `meta_lead_ad`, `highlevel`, `hubspot`, `jobber`, `service_autopilot`, `realgreen`, `sweepandgo`, `deeplawn`, `zapier`, `n8n`, `make`, `crm_import`, `other`, `manual`. |
| `source_detail` | string \| null | yes |  |
| `contact` | object | yes |  |
| `contact.first_name` | string \| null | yes |  |
| `contact.last_name` | string \| null | yes |  |
| `contact.email` | string \| null | yes |  |
| `contact.email_raw` | string \| null |  | The address as received when it is not a valid email (the lead was kept because its phone works). |
| `contact.phone` | string \| null | yes | E.164, or null when the number could not be normalized (see phone_raw). |
| `contact.phone_raw` | string \| null | yes | The number as received (extensions, local or foreign formats are kept here). |
| `contact.phone_verified` | boolean \| null | yes |  |
| `address` | object \| null | yes |  |
| `address.line1` | string \| null | yes |  |
| `address.line2` | string \| null | yes |  |
| `address.city` | string \| null | yes |  |
| `address.region` | string \| null | yes |  |
| `address.postal_code` | string \| null | yes |  |
| `address.country` | string \| null | yes |  |
| `address.formatted` | string | yes | Always present. Components may be null for addresses entered as one line. |
| `address.lat` | number \| null | yes |  |
| `address.lng` | number \| null | yes |  |
| `service_interest` | string \| null | yes | One of: `christmas_lights`, `permanent_lighting`, `landscape_lighting`, `custom`. |
| `service_interest_raw` | string \| null | yes |  |
| `message` | string \| null | yes |  |
| `attribution` | object | yes |  |
| `consent` | object \| null | yes |  |
| `custom_fields` | object | yes |  |
| `notes` | string \| null | yes |  |
| `status_reason` | string \| null | yes |  |
| `client_id` | string \| null | yes | Id prefix `cli_`. |
| `property_id` | string \| null | yes | Id prefix `prop_`. |
| `possible_client_match` | object \| null | yes | An existing client with the same email or phone that this integration was not allowed to update. |
| `possible_client_match.client_id` | string | yes | Id prefix `cli_`. |
| `project` | object \| null | yes |  |
| `project.id` | string | yes | Id prefix `prj_`. |
| `project.status` | string | yes | One of: `intake`, `measuring`, `mockup`, `quote`, `approved`, `completed`, `archived`. |
| `project.pipeline_stage` | string \| null | yes | One of: `request`, `quote_drafted`, `quote_sent`, `approved`, `completed`, `closed_lost`. |
| `project.app_url` | string \| null | yes |  |
| `form` | object \| null |  | The website request form a website_widget lead came from (null for other sources). |
| `form.id` | string | yes | Id prefix `form_`. |
| `form.name` | string | yes |  |
| `mockup_status` | string |  | Instant preview of a website lead: not_requested (the form has no preview), pending (generating), ready (at least one image), failed, or skipped (a fallback applied: low credits, a cap, Off-Season, pause, plan). lead.mockup_ready fires once when it leaves pending. One of: `not_requested`, `pending`, `ready`, `failed`, `skipped`. |
| `form_answers` | object[] |  | Every website request form answer in the form's question order, with its question, group, raw value (the same value as custom_fields[key]) and display labels. Branch questions appear only when they were shown (e.g. tree_count only when trees_bushes is true). Answers to questions the form no longer has come last. An empty array for other sources. |
| `form_answers[].key` | string | yes | Stable answer key, the same key as in custom_fields (e.g. `surfaces`, `primary_color`, `tree_count`, `custom_…`). |
| `form_answers[].question` | string | yes | The question as the form asked it (the key when the form no longer has that question). |
| `form_answers[].group` | string | yes | Answer group: `lighting`, `trees` (trees & bushes), `decor` (wreaths & garland), `details` or `custom` (the contractor's own questions). More groups may be added. |
| `form_answers[].type` | string \| null | yes | Question type (null when the form no longer has the question). One of: `color`, `choice`, `multi_choice`, `toggle`, `text`. |
| `form_answers[].value` | any | yes | The raw answer, identical to custom_fields[key]: a choice value, an array of values, true/false or text. |
| `form_answers[].labels` | string[] | yes | Display labels of the answer in order (toggles: `Yes` or `No`; text: the text). |
| `preview_looks` | string[] |  | The look (light color value, e.g. `warm_white`) of the request's instant preview: an array with at most one item (one AI mockup per request; leads sent before October 2026 may list up to 3, in order). Empty when there is no preview. |
| `offer` | object \| null |  | The website request form's offer (for example "Black Friday: 20% off installs") that was showing when the homeowner sent the request, kept as it was then; null when no offer was active and for other sources. `label` is "20% off", "$150 off" or empty (a headline-only offer). When the request becomes a project, the quote builder pre-fills the quote discount from it once (the contractor can change or remove it); the published quote shows it as `discount` with a `label` such as "Black Friday offer". |
| `offer.template` | string \| null |  | The Light AI campaign template that filled the offer; null or absent for the contractor's own. One of: `classic`, `early_bird`, `black_friday`, `last_chance`. |
| `offer.headline` | string | yes |  |
| `offer.discount_type` | string | yes | One of: `percent`, `amount`. |
| `offer.discount_percent` | integer \| null | yes |  |
| `offer.discount_amount` | integer \| null | yes |  |
| `offer.label` | string | yes |  |
| `offer.ends_at` | string \| null | yes |  |
| `offer.book_by` | string \| null | yes |  |
| `offer.captured_at` | string \| null | yes |  |
| `assets` | object |  | The homeowner's photo and the instant preview images (each with its `look`). GET, list and search answers carry 60-minute signed URLs; webhook payloads and the events feed carry the ids with url null (fetch the lead for fresh links). |
| `assets.photos` | object[] | yes |  |
| `assets.photos[].id` | string | yes | Asset id (`lph_…` photo, `mk_…` preview image). |
| `assets.photos[].url` | string \| null | yes | Signed HTTPS URL valid for 60 minutes (null in webhook payloads, or when the image was removed). |
| `assets.photos[].expires_at` | timestamp \| null | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `assets.mockups` | object[] | yes |  |
| `assets.mockups[].id` | string | yes | Asset id (`lph_…` photo, `mk_…` preview image). |
| `assets.mockups[].url` | string \| null | yes | Signed HTTPS URL valid for 60 minutes (null in webhook payloads, or when the image was removed). |
| `assets.mockups[].expires_at` | timestamp \| null | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `assets.mockups[].look` | string \| null |  | The look (light color) of this preview image: `warm_white`, `cool_white`, `multi`, `candy_cane`, `red_green`, `red_white_green`, `red`, `green`, `blue` or `blue_white` (more may be added). The preview uses the color the homeowner picked (one per request; older leads may have up to 3). Null when unknown. |
| `external_refs` | object[] | yes |  |
| `external_refs[].system` | string | yes |  |
| `external_refs[].namespace` | string \| null | yes |  |
| `external_refs[].id` | string | yes |  |
| `external_refs[].owner` | string | yes | `self`: written by your integration (editable); others are read-only. One of: `self`, `organization`, `partner`. |
| `external_refs[].read_only` | boolean | yes |  |
| `touch_count` | integer | yes |  |
| `last_touched_at` | timestamp \| null | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `submitted_at` | timestamp | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `created_at` | timestamp | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `updated_at` | timestamp | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `replayed` | boolean |  | Present when an external_ref replay returned an existing lead. Always `true`. |
| `fixture` | boolean |  | Test-mode fixture object. Always `true`. |

## Errors

| Status | Meaning |
| --- | --- |
| `400` | Bad request. [`bad_request`](https://docs.light-ai.app/errors#bad_request), [`test_mode_mismatch`](https://docs.light-ai.app/errors#test_mode_mismatch), [`test_mode_unsupported`](https://docs.light-ai.app/errors#test_mode_unsupported), [`unsupported_api_version`](https://docs.light-ai.app/errors#unsupported_api_version) |
| `401` | Missing or invalid credential. [`authentication_required`](https://docs.light-ai.app/errors#authentication_required), [`invalid_api_key`](https://docs.light-ai.app/errors#invalid_api_key), [`api_key_revoked`](https://docs.light-ai.app/errors#api_key_revoked), [`api_key_expired`](https://docs.light-ai.app/errors#api_key_expired), [`api_key_suspended`](https://docs.light-ai.app/errors#api_key_suspended) |
| `403` | Not allowed. [`insufficient_scope`](https://docs.light-ai.app/errors#insufficient_scope), [`plan_upgrade_required`](https://docs.light-ai.app/errors#plan_upgrade_required), [`organization_paused`](https://docs.light-ai.app/errors#organization_paused), [`organization_off_season`](https://docs.light-ai.app/errors#organization_off_season), [`api_disabled`](https://docs.light-ai.app/errors#api_disabled), [`api_access_not_enabled`](https://docs.light-ai.app/errors#api_access_not_enabled), [`ip_not_allowed`](https://docs.light-ai.app/errors#ip_not_allowed), [`forbidden`](https://docs.light-ai.app/errors#forbidden) |
| `404` | Not found (also for objects of other organizations and for organizations without an active grant). |
| `422` | Validation failed. [`idempotency_key_reused`](https://docs.light-ai.app/errors#idempotency_key_reused) |
| `429` | Rate limited or daily cap reached. See Retry-After and the RateLimit headers. [`rate_limited`](https://docs.light-ai.app/errors#rate_limited), [`daily_cap_reached`](https://docs.light-ai.app/errors#daily_cap_reached) |
| `500` | Unexpected server error. Safe to retry with exponential backoff; quote the Request-Id to support. [`internal_error`](https://docs.light-ai.app/errors#internal_error) |
| `503` | Temporarily unavailable. Retry with exponential backoff. [`service_unavailable`](https://docs.light-ai.app/errors#service_unavailable) |

## Examples

**Request**

curl:

```bash
curl -X GET "https://api.light-ai.app/v1/leads/{lead_id}" \
  -H "Authorization: Bearer $LIGHT_AI_API_KEY"
```

JavaScript:

```javascript
const response = await fetch('https://api.light-ai.app/v1/leads/{lead_id}', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_AI_API_KEY}`,
  },
});
const data = await response.json();
```

Python:

```python
import os, uuid, requests

response = requests.get(
    "https://api.light-ai.app/v1/leads/{lead_id}",
    headers={
        "Authorization": f"Bearer {os.environ['LIGHT_AI_API_KEY']}",
    },
    timeout=30,
)
data = response.json()
```

**Response 200**

```json
{
  "id": "lead_3f9c2a7be41d…",
  "object": "lead",
  "livemode": false,
  "status": "new",
  "held": true,
  "needs_address": true,
  "source": "website_widget",
  "source_detail": "string",
  "contact": {
    "first_name": "Dana",
    "last_name": "Reyes",
    "email": "dana@example.com",
    "email_raw": "string",
    "phone": "+15125550134",
    "phone_raw": "string",
    "phone_verified": true
  },
  "address": {
    "line1": "4102 Oak Hollow Dr",
    "line2": "string",
    "city": "Austin",
    "region": "TX",
    "postal_code": "78731",
    "country": "US",
    "formatted": "string",
    "lat": 0,
    "lng": 0
  },
  "service_interest": "christmas_lights",
  "service_interest_raw": "string",
  "message": "string",
  "attribution": {},
  "consent": {},
  "custom_fields": {},
  "notes": "string",
  "status_reason": "string",
  "client_id": "cli_3f9c2a7be41d…",
  "property_id": "prop_3f9c2a7be41d…",
  "possible_client_match": {
    "client_id": "cli_3f9c2a7be41d…"
  },
  "project": {
    "id": "prj_3f9c2a7be41d…",
    "status": "intake",
    "pipeline_stage": "request",
    "app_url": "https://example.com/…"
  },
  "form": {
    "id": "form_3f9c2a7be41d…",
    "name": "Dana Reyes"
  },
  "mockup_status": "not_requested",
  "form_answers": [
    {
      "key": "surfaces",
      "question": "What should we light?",
      "group": "lighting",
      "type": "multi_choice",
      "value": [
        "eaves",
        "garage"
      ],
      "labels": [
        "Roof peaks + gutters",
        "Garage doors"
      ]
    }
  ],
  "preview_looks": [
    "warm_white"
  ],
  "offer": {
    "template": "black_friday",
    "headline": "Black Friday: 20% off installs",
    "discount_type": "percent",
    "discount_percent": 20,
    "discount_amount": null,
    "label": "20% off",
    "ends_at": "2026-11-30T05:59:00Z",
    "book_by": "Book by Dec 1 for install before Christmas",
    "captured_at": "2026-11-27T14:03:11Z"
  },
  "assets": {
    "photos": [
      {
        "id": "string",
        "url": "https://example.com/…",
        "expires_at": "2026-10-12T14:03:11.000Z"
      }
    ],
    "mockups": [
      {
        "id": "string",
        "url": "https://example.com/…",
        "expires_at": "2026-10-12T14:03:11.000Z",
        "look": "warm_white"
      }
    ]
  },
  "external_refs": [
    {
      "system": "string",
      "namespace": "string",
      "id": "string",
      "owner": "self",
      "read_only": true
    }
  ],
  "touch_count": 1,
  "last_touched_at": "2026-10-12T14:03:11.000Z",
  "submitted_at": "2026-10-12T14:03:11.000Z",
  "created_at": "2026-10-12T14:03:11.000Z",
  "updated_at": "2026-10-12T14:03:11.000Z",
  "replayed": true,
  "fixture": true
}
```
