API reference
GETList leads
GET /v1/leads: Newest first by default.
GET
https://api.light-ai.app/v1/leadsNewest first by default. For an incremental sync use sort=updated_asc&updated_since=…, follow next_cursor, and start the next poll a few minutes before your last updated_at (de-duplicate by id): a late commit can carry an earlier timestamp. For a gapless change feed poll GET /v1/events?sort=sync_asc.
| 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. |
Query parameters#
Page size, 1–100 (default 25). 1–100.
next_cursor from the previous page. At most 400 characters.
updated_asc pages objects in last-change order (for an initial or incremental sync with updated_since). A write that commits late can carry an earlier updated_at, so re-poll from your high-water mark minus 5 minutes and de-duplicate by id + updated_at; GET /v1/events?sort=sync_asc is the gapless change feed. One of: created_desc, updated_asc.One of:
new, converted, spam, archived, duplicate, held.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.Only objects created after this time.
Only objects created before this time.
Only objects updated after this time (alias: updated_after). Overlap polls by a few minutes: see sort.
Alias of updated_since.
<system>:<id> in your own namespace, e.g. jobber:Z2lk123. At most 400 characters.At most 120 characters.
Only leads from this website request form (
form_…). Id prefix form_.Headers#
Partner keys: the connected organization to act for (
org_…). Organization keys may omit it. Id prefix org_.Pin a dated API version (defaults to the key's version). One of:
2026-11-01.Response 200#
A page of leads.
Always
list.Id prefix
lead_.Always
lead.false for objects created with a test key.
One of:
new, converted, spam, archived, duplicate.Accepted while the organization was paused; converts automatically on resume.
A lead without a street address (none, or only a ZIP, city or region) waits for one (PATCH /v1/leads/{id} with address).
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.The address as received when it is not a valid email (the lead was kept because its phone works).
E.164, or null when the number could not be normalized (see phone_raw).
The number as received (extensions, local or foreign formats are kept here).
Always present. Components may be null for addresses entered as one line.
One of:
christmas_lights, permanent_lighting, landscape_lighting, custom.Id prefix
cli_.Id prefix
prop_.An existing client with the same email or phone that this integration was not allowed to update.
Id prefix
cli_.Id prefix
prj_.One of:
intake, measuring, mockup, quote, approved, completed, archived.One of:
request, quote_drafted, quote_sent, approved, completed, closed_lost.The website request form a website_widget lead came from (null for other sources).
Id prefix
form_.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.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.
Stable answer key, the same key as in custom_fields (e.g.
surfaces, primary_color, tree_count, custom_…).The question as the form asked it (the key when the form no longer has that question).
Answer group:
lighting, trees (trees & bushes), decor (wreaths & garland), details or custom (the contractor's own questions). More groups may be added.Question type (null when the form no longer has the question). One of:
color, choice, multi_choice, toggle, text.The raw answer, identical to custom_fields[key]: a choice value, an array of values, true/false or text.
Display labels of the answer in order (toggles:
Yes or No; text: the text).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.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".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.One of:
percent, amount.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).self: written by your integration (editable); others are read-only. One of: self, organization, partner.RFC 3339 timestamp (UTC, milliseconds).
RFC 3339 timestamp (UTC, milliseconds).
RFC 3339 timestamp (UTC, milliseconds).
RFC 3339 timestamp (UTC, milliseconds).
Present when an external_ref replay returned an existing lead. Always
true.Test-mode fixture object. Always
true.Pass as
cursor to fetch the next page.Errors#
| Status | Meaning |
|---|---|
400 | Bad request. bad_request, test_mode_mismatch, test_mode_unsupported, unsupported_api_version |
401 | Missing or invalid credential. authentication_required, invalid_api_key, api_key_revoked, api_key_expired, api_key_suspended |
403 | Not allowed. insufficient_scope, plan_upgrade_required, organization_paused, organization_off_season, api_disabled, api_access_not_enabled, ip_not_allowed, forbidden |
404 | Not found (also for objects of other organizations and for organizations without an active grant). |
422 | Validation failed. idempotency_key_reused |
429 | Rate limited or daily cap reached. See Retry-After and the RateLimit headers. rate_limited, daily_cap_reached |
500 | Unexpected server error. Safe to retry with exponential backoff; quote the Request-Id to support. internal_error |
503 | Temporarily unavailable. Retry with exponential backoff. service_unavailable |