Leads
Base URL: https://api.klozeo.com/api/v1
Auth: X-API-Key: sk_live_... required on all requests.
ID format
Section titled “ID format”Lead IDs use the prefix cl_ (e.g., cl_01234567-89ab-cdef-0123-456789abcdef). Always include the full ID with the prefix in API requests.
Lead object
Section titled “Lead object”| Field | Type | Notes |
|---|---|---|
id | string | Format: cl_<uuid>. Read-only. |
name | string | Required |
source | string | Required |
email | string | Optional |
phone | string | Optional |
city | string | Optional |
website | string | Optional |
rating | number | Optional. Useful in scoring expressions. |
tags | string[] | Optional array |
score | number | 0–100. Computed via scoring rules. |
source_id | string | Optional. External ID used for deduplication. |
created_at | integer | Unix seconds. Read-only. |
updated_at | integer | Unix seconds. Updated only when a structural field changes. |
last_interaction_at | integer | Unix seconds. Updated on every push or merge. |
All timestamps are Unix seconds (not milliseconds). For JavaScript: new Date(timestamp * 1000).
List Leads
Section titled “List Leads”GET /leads| Parameter | Type | Default | Description |
|---|---|---|---|
filter | string | — | Repeatable. Format: logic.operator.field.value. Example: filter=and.eq.city.Paris. See Filtering guide → |
sort_by | string | — | Field to sort by |
sort_order | string | ASC | ASC or DESC |
limit | integer | 50 | Max results (max: 1000) |
cursor | string | — | Opaque pagination token from previous response |
Response 200 OK:
{ "leads": [{ "id": "cl_...", "name": "Acme", "source": "website", "score": 87, "..." }], "next_cursor": "eyJpZCI6ImNsXzAxMjM...", "has_more": true, "count": 50}Create Lead
Section titled “Create Lead”POST /leadsRequired fields: name, source. All other fields are optional.
{ "name": "Acme Corporation", "source": "website", "email": "contact@acme.com", "city": "San Francisco", "rating": 4.5, "tags": ["enterprise"], "attributes": [ { "name": "industry", "type": "text", "value": "Software" }, { "name": "employees", "type": "number", "value": 500 } ]}Automatic deduplication runs before every insert. The response varies depending on the outcome:
// New lead created (201 Created){ "id": "cl_...", "message": "Lead created successfully", "created_at": 1703520000 }
// Duplicate detected and merged (200 OK){ "id": "cl_existing...", "message": "Duplicate detected, existing lead updated", "created_at": 1703520000, "duplicate": true }
// Low-confidence match — new lead created with a hint (201 Created){ "id": "cl_new...", "message": "Lead created successfully", "potential_duplicate_id": "cl_similar..." }Deduplication priority:
| Priority | Criterion | Confidence | Action |
|---|---|---|---|
| 1 | email match (case-insensitive) | High | Merge → 200 + "duplicate": true |
| 2 | source_id match (exact) | High | Merge → 200 + "duplicate": true |
| 3 | phone + name similarity > 80% | Medium | Merge → 200 + "duplicate": true |
| 4 | name + city match | Low | Create + "potential_duplicate_id" |
Merge strategy: Last Touch Wins — non-empty incoming fields overwrite existing. last_interaction_at is always bumped.
Error 403 when the free plan lead limit (100) is reached.
Get Lead
Section titled “Get Lead”GET /leads/{id}Response 200 OK: Full lead object (see schema above).
Error 404 if the lead does not exist or belongs to a different account.
Update Lead
Section titled “Update Lead”PUT /leads/{id}Partial update — only include fields to change. Returns the updated lead.
{ "rating": 4.8, "city": "New York", "tags": ["enterprise", "updated"] }Error 404 if the lead does not exist or belongs to a different account.
Delete Lead
Section titled “Delete Lead”DELETE /leads/{id}Response 204 No Content.
Error 404 if the lead does not exist or belongs to a different account.
Batch Create
Section titled “Batch Create”POST /leads/batch⚠️ Deduplication not included Batch create skips duplicate detection for performance. If you need deduplication, use
POST /leadsindividually or pre-deduplicate your dataset before importing.
Up to 100 leads (Free) or 500 leads (Pro) per request. Exceeding the limit returns 400 Bad Request — the entire request is rejected and no leads are created.
{ "leads": [ { "name": "Lead 1", "source": "import", "city": "Athens" }, { "name": "Lead 2", "source": "import", "city": "London" } ]}Response 201 Created (all succeeded) or 207 Multi-Status (partial failure):
207 Multi-Statusmeans at least one lead failed. Always check theerrorsarray, even when the request returned 207 and not a 4xx/5xx. Entries increatedwere saved successfully.
{ "created": [{ "index": 0, "id": "cl_...", "created_at": 1703520000 }], "errors": [{ "index": 1, "message": "Duplicate source_id" }], "total": 2, "success": 1, "failed": 1}Batch Update
Section titled “Batch Update”PUT /leads/batchApply the same partial update to multiple leads:
{ "ids": ["cl_aaa...", "cl_bbb..."], "data": { "category": "Technology" }}Batch Delete
Section titled “Batch Delete”DELETE /leads/batch{ "ids": ["cl_aaa...", "cl_bbb..."] }Recalculate Score
Section titled “Recalculate Score”POST /leads/{id}/scoreRecalculates and persists the score for a single lead based on current scoring rules.
Bulk Recalculate Scores
Section titled “Bulk Recalculate Scores”POST /leads/score/batchRecalculates scores for all leads in your account.
Export
Section titled “Export”GET /leads/export?format=csvSee the Export reference for full details.
Common errors
Section titled “Common errors”| Status | Code | Description |
|---|---|---|
| 400 | bad_request | Invalid request body or parameters (e.g., missing required fields, batch limit exceeded) |
| 401 | unauthorized | Missing or invalid API key |
| 403 | leads_limit_reached | Free plan lead limit reached — upgrade to Pro |
| 404 | not_found | Lead not found or belongs to a different account |
| 429 | rate_limit_exceeded | Rate limit exceeded — see Rate Limits |
| 500 | internal_error | Internal server error |