Enrichment API
Public enrichment is asynchronous. You submit contacts in bulk, receive identifiers, then poll or use webhooks for completion.
Start Bulk Enrichment
POST /api/v1/public/enrich/bulk
curl -X POST https://api.cleanlist.ai/api/v1/public/enrich/bulk \
-H "Authorization: Bearer clapi_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"enrichment_type": "partial",
"contacts": [
{
"linkedin_url": "https://linkedin.com/in/johndoe",
"first_name": "John",
"last_name": "Doe",
"company_domain": "acme.com"
},
{
"first_name": "Jane",
"last_name": "Smith",
"company_name": "Example Inc"
}
]
}'Request Body
| Field | Type | Required | Description |
|---|---|---|---|
enrichment_type | string | Yes | none, partial, phone_only, or full |
contacts | array | Yes | Up to 250 contacts per request |
Contact Input Requirements
Each contact must include one of these two input patterns:
linkedin_urlfirst_name+last_name+ (company_nameorcompany_domain)
If contacts exceeds 250, the API returns 400 with a validation error.
LinkedIn-Only Payload Example
{
"enrichment_type": "full",
"contacts": [
{
"linkedin_url": "https://www.linkedin.com/in/levon-adamyan"
}
]
}Enrichment Types
| Type | Behavior | Typical use |
|---|---|---|
none | Normalize and prepare records only | Stage/import contacts without appending new contact data |
partial | Email enrichment | Find and verify business emails |
phone_only | Phone enrichment | Find direct phone numbers |
full | Email + phone enrichment | Max contact coverage |
Response
{
"workflow_id": "public_bulk_3d1f9a67-cc44-4a06-b8d4-7fe7a8f31a01",
"status": "processing",
"message": "Bulk enrichment started",
"task_ids": [
"6aab5e77-f5c0-4233-8f8e-a0e1a9baf18c",
"d2c1e5f2-2d83-47f2-a620-4d27906b9f65"
],
"total_contacts": 2
}The API validates credit availability before processing. If insufficient, the request can return 402.
Poll Enrichment Status
GET /api/v1/public/enrich/status
Provide exactly one query parameter:
workflow_idfor aggregate workflow progresstask_idfor single task status
Workflow Status Example
curl "https://api.cleanlist.ai/api/v1/public/enrich/status?workflow_id=public_bulk_3d1f9a67-cc44-4a06-b8d4-7fe7a8f31a01" \
-H "Authorization: Bearer clapi_your_api_key"Task Status Example
curl "https://api.cleanlist.ai/api/v1/public/enrich/status?task_id=6aab5e77-f5c0-4233-8f8e-a0e1a9baf18c" \
-H "Authorization: Bearer clapi_your_api_key"Response (task):
{
"task": {
"task_id": "6aab5e77-f5c0-4233-8f8e-a0e1a9baf18c",
"status": "completed",
"message": "Enrichment completed"
}
}Webhooks
Register Webhook
POST /api/v1/public/webhooks
curl -X POST https://api.cleanlist.ai/api/v1/public/webhooks \
-H "Authorization: Bearer clapi_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://example.com/cleanlist-webhooks",
"name": "Production Enrichment Webhook",
"event_type": "enrichment.completed"
}'List Delivery Attempts
GET /api/v1/public/webhooks/deliveries?workflow_id=<workflow_id>
curl "https://api.cleanlist.ai/api/v1/public/webhooks/deliveries?workflow_id=public_bulk_3d1f9a67-cc44-4a06-b8d4-7fe7a8f31a01" \
-H "Authorization: Bearer clapi_your_api_key"Polling Best Practice
Use backoff when polling status:
import time
import requests
def poll_workflow(workflow_id, api_key, max_wait=300):
url = "https://api.cleanlist.ai/api/v1/public/enrich/status"
headers = {"Authorization": f"Bearer {api_key}"}
delay = 1
elapsed = 0
while elapsed < max_wait:
response = requests.get(url, headers=headers, params={"workflow_id": workflow_id})
data = response.json()
workflow = data.get("workflow", {})
if workflow.get("status") in ("completed", "failed"):
return workflow
time.sleep(delay)
elapsed += delay
delay = min(delay * 2, 10)
raise TimeoutError(f"Workflow {workflow_id} did not complete within {max_wait}s")Rate Limits
Public endpoints documented on this page are limited to 60 requests per minute per organization in a fixed 60-second window.
If you exceed the limit, the API returns 429 Too Many Requests with a Retry-After header.
Example 429 response:
HTTP/1.1 429 Too Many Requests
Retry-After: 17
Content-Type: application/json
{
"detail": "Rate limit exceeded. Public API is limited to 60 requests per minute."
}