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.
POST
https://api.light-ai.app/v1/clientsMatches 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.
| Scope | clients:write |
|---|---|
| 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. |
| Idempotency | Idempotency-Key supported. See Idempotency. |
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.Retry-safe writes: the same key and body replay the first response for 24 hours (
Idempotent-Replayed: true). 8–128 characters.Request body#
At most 100 characters.
At most 100 characters.
An email address ("" or null: absent). At most 254 characters.
At most 40 characters.
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.
At most 200 characters.
At most 200 characters.
At most 120 characters.
State or region, e.g.
TX. At most 120 characters.At most 20 characters.
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.
A one-line address, when components are not available. At most 500 characters.
-90–90.
-180–180.
Google place id, when known (best dedupe key). At most 300 characters.
Matched first (your namespace only), then email, then phone.
Lowercase system name, e.g.
jobber, hubspot, highlevel.Optional sub-namespace in that system (e.g. an account id). null or "": none. At most 120 characters.
1–255 characters.
The system that caused this write (shown as origin.source_system on the resulting events, for loop prevention).
Response 200#
Existing client updated.
Id prefix
cli_.Always
client.false for objects created with a test key.
E.164, or null when the stored number could not be normalized (see phone_raw).
The number as stored in Light AI.
Id prefix
prop_.Always
property.Id prefix
cli_.Always present. Components may be null for addresses entered as one line.
RFC 3339 timestamp (UTC, milliseconds).
RFC 3339 timestamp (UTC, milliseconds).
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).
Always
true.Response 201#
Client created.
Id prefix
cli_.Always
client.false for objects created with a test key.
E.164, or null when the stored number could not be normalized (see phone_raw).
The number as stored in Light AI.
Id prefix
prop_.Always
property.Id prefix
cli_.Always present. Components may be null for addresses entered as one line.
RFC 3339 timestamp (UTC, milliseconds).
RFC 3339 timestamp (UTC, milliseconds).
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).
Always
true.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). |
409 | Conflict. stale_state, conflict, idempotency_in_progress, idempotency_scope_mismatch, quote_already_decided, quote_not_current, billing_review_required |
413 | Request bodies are limited to 256 KB. |
415 | The body is not JSON: send Content-Type: application/json. unsupported_media_type |
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 |