Concepts
Idempotency
Send an Idempotency-Key with writes so retries never create duplicates or charge twice.
Add Idempotency-Key (8–128 visible ASCII characters; a UUID is ideal) to write requests (POST and PATCH; each reference page says whether it applies). The same key with the same body replays the first response for 24 hours, with Idempotent-Replayed: true.
curl -X POST "https://api.light-ai.app/v1/leads" \
-H "Authorization: Bearer $LIGHT_AI_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"source": "api",
"contact": {
"first_name": "Dana",
"email": "dana@example.com"
}
}'const response = await fetch('https://api.light-ai.app/v1/leads', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LIGHT_AI_API_KEY}`,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
"source": "api",
"contact": {
"first_name": "Dana",
"email": "dana@example.com"
}
}),
});
const data = await response.json();import os, uuid, requests
response = requests.post(
"https://api.light-ai.app/v1/leads",
headers={
"Authorization": f"Bearer {os.environ['LIGHT_AI_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"source": "api",
"contact": {
"first_name": "Dana",
"email": "dana@example.com"
}
},
)
data = response.json()| Situation | Answer |
|---|---|
| Same key, same body, first request finished | The stored response, Idempotent-Replayed: true |
| Same key while the first is still running | Waits for the first to finish, then answers with its stored response (Idempotent-Replayed: true); if the first failed, the retry runs as a new request |
| Same key, different body | 422 idempotency_key_reused |
Mockups#
POST /v1/projects/{id}/mockups requires the header, and its replay is permanent (not only 24 hours): a retry with the same key returns the same generation and never charges again. For live keys it is scoped to the organization and your partner account (or the organization alone for organization keys), not to one API key, so a retry after rolling a key is still safe.
Keys in automation tools#
Use a value that is stable across retries of one logical request, ideally the source record id (meta-{{leadgen_id}}). In n8n without one, use {{$execution.id}}-{{$runIndex}}-{{$itemIndex}} so each item gets its own key. Idempotency keys are scoped to your API key and the organization (and live or test mode), so one partner workflow is safe across contractors.
Leads have a second safety net: an external_ref your integration already sent replays the original lead (replayed: true) at any time, not only within 24 hours.