Light AIDocs Beta Open Light AI

API reference

GETRetrieve a lead

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

GEThttps://api.light-ai.app/v1/leads/{lead_id}
Scopeleads:read
CredentialAPI key: Authorization: Bearer lai_live_… (or lai_test_…). Partner keys add Light-AI-Organization.
Test modeWorks with test keys against simulated test objects.

Path parameters#

lead_idstringrequired#
The lead id (lead_…). Id prefix lead_.

Headers#

Light-AI-Organizationstring#
Partner keys: the connected organization to act for (org_…). Organization keys may omit it. Id prefix org_.
Light-AI-Versionstring#
Pin a dated API version (defaults to the key's version). One of: 2026-11-01.

Response 200#

The lead.

idstringrequired#
Id prefix lead_.
objectstringrequired#
Always lead.
livemodebooleanrequired#
false for objects created with a test key.
statusstringrequired#
One of: new, converted, spam, archived, duplicate.
heldbooleanrequired#
Accepted while the organization was paused; converts automatically on resume.
needs_addressbooleanrequired#
A lead without a street address (none, or only a ZIP, city or region) waits for one (PATCH /v1/leads/{id} with address).
sourcestringrequired#
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_detailstring | nullrequired#
contactobjectrequired#
contact.first_namestring | nullrequired#
contact.last_namestring | nullrequired#
contact.emailstring | nullrequired#
contact.email_rawstring | null#
The address as received when it is not a valid email (the lead was kept because its phone works).
contact.phonestring | nullrequired#
E.164, or null when the number could not be normalized (see phone_raw).
contact.phone_rawstring | nullrequired#
The number as received (extensions, local or foreign formats are kept here).
contact.phone_verifiedboolean | nullrequired#
addressobject | nullrequired#
address.line1string | nullrequired#
address.line2string | nullrequired#
address.citystring | nullrequired#
address.regionstring | nullrequired#
address.postal_codestring | nullrequired#
address.countrystring | nullrequired#
address.formattedstringrequired#
Always present. Components may be null for addresses entered as one line.
address.latnumber | nullrequired#
address.lngnumber | nullrequired#
service_intereststring | nullrequired#
One of: christmas_lights, permanent_lighting, landscape_lighting, custom.
service_interest_rawstring | nullrequired#
messagestring | nullrequired#
attributionobjectrequired#
custom_fieldsobjectrequired#
notesstring | nullrequired#
status_reasonstring | nullrequired#
client_idstring | nullrequired#
Id prefix cli_.
property_idstring | nullrequired#
Id prefix prop_.
possible_client_matchobject | nullrequired#
An existing client with the same email or phone that this integration was not allowed to update.
possible_client_match.client_idstringrequired#
Id prefix cli_.
projectobject | nullrequired#
project.idstringrequired#
Id prefix prj_.
project.statusstringrequired#
One of: intake, measuring, mockup, quote, approved, completed, archived.
project.pipeline_stagestring | nullrequired#
One of: request, quote_drafted, quote_sent, approved, completed, closed_lost.
project.app_urlstring | nullrequired#
formobject | null#
The website request form a website_widget lead came from (null for other sources).
form.idstringrequired#
Id prefix form_.
form.namestringrequired#
mockup_statusstring#
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_answersobject[]#
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[].keystringrequired#
Stable answer key, the same key as in custom_fields (e.g. surfaces, primary_color, tree_count, custom_…).
form_answers[].questionstringrequired#
The question as the form asked it (the key when the form no longer has that question).
form_answers[].groupstringrequired#
Answer group: lighting, trees (trees & bushes), decor (wreaths & garland), details or custom (the contractor's own questions). More groups may be added.
form_answers[].typestring | nullrequired#
Question type (null when the form no longer has the question). One of: color, choice, multi_choice, toggle, text.
form_answers[].valueanyrequired#
The raw answer, identical to custom_fields[key]: a choice value, an array of values, true/false or text.
form_answers[].labelsstring[]required#
Display labels of the answer in order (toggles: Yes or No; text: the text).
preview_looksstring[]#
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.
offerobject | 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.templatestring | 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.headlinestringrequired#
offer.discount_typestringrequired#
One of: percent, amount.
offer.discount_percentinteger | nullrequired#
offer.discount_amountinteger | nullrequired#
offer.labelstringrequired#
offer.ends_atstring | nullrequired#
offer.book_bystring | nullrequired#
offer.captured_atstring | nullrequired#
assetsobject#
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.photosobject[]required#
assets.photos[].idstringrequired#
Asset id (lph_… photo, mk_… preview image).
assets.photos[].urlstring | nullrequired#
Signed HTTPS URL valid for 60 minutes (null in webhook payloads, or when the image was removed).
assets.photos[].expires_attimestamp | nullrequired#
RFC 3339 timestamp (UTC, milliseconds).
assets.mockupsobject[]required#
assets.mockups[].idstringrequired#
Asset id (lph_… photo, mk_… preview image).
assets.mockups[].urlstring | nullrequired#
Signed HTTPS URL valid for 60 minutes (null in webhook payloads, or when the image was removed).
assets.mockups[].expires_attimestamp | nullrequired#
RFC 3339 timestamp (UTC, milliseconds).
assets.mockups[].lookstring | 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_refsobject[]required#
external_refs[].systemstringrequired#
external_refs[].namespacestring | nullrequired#
external_refs[].idstringrequired#
external_refs[].ownerstringrequired#
self: written by your integration (editable); others are read-only. One of: self, organization, partner.
external_refs[].read_onlybooleanrequired#
touch_countintegerrequired#
last_touched_attimestamp | nullrequired#
RFC 3339 timestamp (UTC, milliseconds).
submitted_attimestamprequired#
RFC 3339 timestamp (UTC, milliseconds).
created_attimestamprequired#
RFC 3339 timestamp (UTC, milliseconds).
updated_attimestamprequired#
RFC 3339 timestamp (UTC, milliseconds).
replayedboolean#
Present when an external_ref replay returned an existing lead. Always true.
fixtureboolean#
Test-mode fixture object. Always true.

Errors#

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