Light AIDocs Beta Open Light AI

API reference

POSTCreate or update a client

POST /v1/clients: Matches your own external_ref first, then the exact email, then the phone; otherwise creates the client.

POSThttps://api.light-ai.app/v1/clients

Matches your own external_ref first, then the exact email, then the phone; otherwise creates the client. An address adds that property when it is new for the client. Without clients:read the answer carries the id only.

Scopeclients:write
CredentialAPI key: Authorization: Bearer lai_live_… (or lai_test_…). Partner keys add Light-AI-Organization.
Test modeWorks with test keys against simulated test objects.
IdempotencyIdempotency-Key supported. See Idempotency.

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.
Idempotency-Keystring#
Retry-safe writes: the same key and body replay the first response for 24 hours (Idempotent-Replayed: true). 8–128 characters.

Request body#

first_namestring | null#
At most 100 characters.
last_namestring | null#
At most 100 characters.
emailstring | null#
An email address ("" or null: absent). At most 254 characters.
phonestring | null#
At most 40 characters.
addressobject | null#
Adds this property when it is a street address (a line1, a formatted line that starts with the house number, or a place_id) new for the client. A partial address (only a ZIP, city or region, as CRMs send for most contacts) is ignored.
address.line1string | null#
At most 200 characters.
address.line2string | null#
At most 200 characters.
address.citystring | null#
At most 120 characters.
address.regionstring | null#
State or region, e.g. TX. At most 120 characters.
address.postal_codestring | null#
At most 20 characters.
address.countrystring | null#
ISO 3166-1 alpha-2 in any case, or a common name ("USA", "United States"); normalized to alpha-2. Defaults to US. At most 60 characters.
address.formattedstring | null#
A one-line address, when components are not available. At most 500 characters.
address.latnumber | null#
-90–90.
address.lngnumber | null#
-180–180.
address.place_idstring | null#
Google place id, when known (best dedupe key). At most 300 characters.
external_refobject | null#
Matched first (your namespace only), then email, then phone.
external_ref.systemstringrequired#
Lowercase system name, e.g. jobber, hubspot, highlevel.
external_ref.namespacestring | null#
Optional sub-namespace in that system (e.g. an account id). null or "": none. At most 120 characters.
external_ref.idstringrequired#
1–255 characters.
source_systemstring | null#
The system that caused this write (shown as origin.source_system on the resulting events, for loop prevention).

Response 200#

Existing client updated.

idstring#
Id prefix cli_.
objectstring#
Always client.
livemodeboolean#
false for objects created with a test key.
first_namestring | null#
last_namestring | null#
emailstring | null#
phonestring | null#
E.164, or null when the stored number could not be normalized (see phone_raw).
phone_rawstring | null#
The number as stored in Light AI.
primary_propertyobject | null#
primary_property.idstringrequired#
Id prefix prop_.
primary_property.objectstringrequired#
Always property.
primary_property.client_idstring | nullrequired#
Id prefix cli_.
primary_property.is_primarybooleanrequired#
primary_property.property_typestring | nullrequired#
primary_property.addressobject | nullrequired#
primary_property.address.line1string | nullrequired#
primary_property.address.line2string | nullrequired#
primary_property.address.citystring | nullrequired#
primary_property.address.regionstring | nullrequired#
primary_property.address.postal_codestring | nullrequired#
primary_property.address.countrystring | nullrequired#
primary_property.address.formattedstringrequired#
Always present. Components may be null for addresses entered as one line.
primary_property.address.latnumber | nullrequired#
primary_property.address.lngnumber | nullrequired#
primary_property.created_attimestamprequired#
RFC 3339 timestamp (UTC, milliseconds).
primary_property.updated_attimestamprequired#
RFC 3339 timestamp (UTC, milliseconds).
property_countinteger#
external_refsobject[]#
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#
created_attimestamp#
RFC 3339 timestamp (UTC, milliseconds).
updated_attimestamp#
RFC 3339 timestamp (UTC, milliseconds).
fixtureboolean#
Always true.

Response 201#

Client created.

idstring#
Id prefix cli_.
objectstring#
Always client.
livemodeboolean#
false for objects created with a test key.
first_namestring | null#
last_namestring | null#
emailstring | null#
phonestring | null#
E.164, or null when the stored number could not be normalized (see phone_raw).
phone_rawstring | null#
The number as stored in Light AI.
primary_propertyobject | null#
primary_property.idstringrequired#
Id prefix prop_.
primary_property.objectstringrequired#
Always property.
primary_property.client_idstring | nullrequired#
Id prefix cli_.
primary_property.is_primarybooleanrequired#
primary_property.property_typestring | nullrequired#
primary_property.addressobject | nullrequired#
primary_property.address.line1string | nullrequired#
primary_property.address.line2string | nullrequired#
primary_property.address.citystring | nullrequired#
primary_property.address.regionstring | nullrequired#
primary_property.address.postal_codestring | nullrequired#
primary_property.address.countrystring | nullrequired#
primary_property.address.formattedstringrequired#
Always present. Components may be null for addresses entered as one line.
primary_property.address.latnumber | nullrequired#
primary_property.address.lngnumber | nullrequired#
primary_property.created_attimestamprequired#
RFC 3339 timestamp (UTC, milliseconds).
primary_property.updated_attimestamprequired#
RFC 3339 timestamp (UTC, milliseconds).
property_countinteger#
external_refsobject[]#
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#
created_attimestamp#
RFC 3339 timestamp (UTC, milliseconds).
updated_attimestamp#
RFC 3339 timestamp (UTC, milliseconds).
fixtureboolean#
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).
409Conflict. stale_state, conflict, idempotency_in_progress, idempotency_scope_mismatch, quote_already_decided, quote_not_current, billing_review_required
413Request bodies are limited to 256 KB.
415The body is not JSON: send Content-Type: application/json. unsupported_media_type
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