Contacts represent the people in your CRM — leads, customers, prospects, and anyone else captured by your agents or imported from another system. Every contact belongs to a specific agent (bot_id) and inherits the workspace from your API key.
Unique contact identifier.
The workspace this contact belongs to.
The agent that owns this contact.
Array of { email, is_primary } objects. The first item is treated as primary if no is_primary flag is set.
Array of { phone_number, is_primary } objects.
Free-text company name. Use company_id to link to a structured Company record.
Estimated deal value as a number (currency assumed to match workspace settings).
Current stage in a sales pipeline.
Free-form classification (e.g. "lead", "customer").
Workspace-defined custom fields, stored as a free-form JSON object.
ISO 8601 timestamp of the most recent activity.
Returns a paginated list of contacts in the workspace.
Query parameters
| Param | Type | Description |
|---|
search | string | Match against name, email, phone, or company |
tags | string | Comma-separated list of tags to filter by |
lead_source | string | Filter by lead source |
pipeline_stage_id | string | Filter to contacts in a specific pipeline stage |
bot_id | string | Filter to contacts owned by a specific agent |
created_after | string (ISO 8601) | Created at or after this timestamp |
created_before | string (ISO 8601) | Created at or before this timestamp |
updated_after | string (ISO 8601) | Updated at or after this timestamp |
page | integer | See Pagination |
page_size | integer | See Pagination |
Example
curl "https://clarky.ai/api/v1/contacts?search=ada&page_size=10" \
-H "Authorization: Bearer ck_live_example"
{
"data": [
{
"id": "c_01HXYZ...",
"workspace_id": "w_01HABC...",
"bot_id": "b_01HDEF...",
"first_name": "Ada",
"last_name": "Lovelace",
"emails": [{ "email": "ada@example.com", "is_primary": true }],
"phone_numbers": [],
"company": "Analytical Engines Inc.",
"company_id": null,
"job_title": "Founder",
"lead_source": "website",
"tags": ["vip"],
"deal_value": 25000,
"pipeline_stage_id": "ps_01HGHI...",
"contact_type": "lead",
"address_line1": null,
"address_line2": null,
"city": "London",
"state": null,
"postal_code": null,
"country": "UK",
"linkedin_url": null,
"notes": null,
"custom_fields": {},
"last_contacted_at": "2026-04-29T14:00:00.000Z",
"created_at": "2026-04-12T09:30:00.000Z",
"updated_at": "2026-04-29T14:00:00.000Z"
}
],
"pagination": { "page": 1, "page_size": 10, "total": 1, "total_pages": 1 }
}
GET /api/v1/contacts/by-email
Looks up a single contact by primary email address. Returns 404 not_found if no contact matches.
Query parameters
| Param | Type | Required | Description |
|---|
email | string | Yes | Email to match (case-insensitive) |
Example
curl "https://clarky.ai/api/v1/contacts/by-email?email=ada@example.com" \
-H "Authorization: Bearer ck_live_example"
{
"data": {
"id": "c_01HXYZ...",
"first_name": "Ada",
"last_name": "Lovelace",
"emails": [{ "email": "ada@example.com", "is_primary": true }],
"phone_numbers": [],
"company": "Analytical Engines Inc.",
"tags": ["vip"],
"created_at": "2026-04-12T09:30:00.000Z",
"updated_at": "2026-04-29T14:00:00.000Z"
}
}
GET /api/v1/contacts/{id}
Example
curl https://clarky.ai/api/v1/contacts/c_01HXYZ \
-H "Authorization: Bearer ck_live_example"
{
"data": {
"id": "c_01HXYZ...",
"first_name": "Ada",
"last_name": "Lovelace",
"emails": [{ "email": "ada@example.com", "is_primary": true }],
"phone_numbers": [],
"tags": ["vip"],
"created_at": "2026-04-12T09:30:00.000Z",
"updated_at": "2026-04-29T14:00:00.000Z"
}
}
Requires a key with the write scope.
Body fields
| Field | Type | Required | Description |
|---|
bot_id | string | Yes | Agent that should own this contact |
first_name | string | No | |
last_name | string | No | |
emails | array | No | Array of { email, is_primary } |
phone_numbers | array | No | Array of { phone_number, is_primary } |
company | string | No | Free-text company name |
company_id | string | No | Link to an existing Company |
job_title | string | No | |
lead_source | string | No | |
tags | string[] | No | |
deal_value | number | No | |
pipeline_stage_id | string | No | |
contact_type | string | No | |
address_line1 | string | No | |
address_line2 | string | No | |
city | string | No | |
state | string | No | |
postal_code | string | No | |
country | string | No | |
linkedin_url | string | No | |
notes | string | No | |
custom_fields | object | No | |
Example
curl https://clarky.ai/api/v1/contacts \
-H "Authorization: Bearer ck_live_example" \
-H "Content-Type: application/json" \
-d '{
"bot_id": "b_01HDEF",
"first_name": "Ada",
"last_name": "Lovelace",
"emails": [{ "email": "ada@example.com", "is_primary": true }],
"company": "Analytical Engines Inc.",
"tags": ["vip"]
}'
{
"data": {
"id": "c_01HXYZ...",
"first_name": "Ada",
"last_name": "Lovelace",
"emails": [{ "email": "ada@example.com", "is_primary": true }],
"company": "Analytical Engines Inc.",
"tags": ["vip"],
"created_at": "2026-04-29T18:42:00.000Z",
"updated_at": "2026-04-29T18:42:00.000Z"
}
}
PATCH /api/v1/contacts/{id}
Updates the listed fields and leaves everything else untouched. Same fields as Create a contact, except bot_id cannot be changed.
Example
curl -X PATCH https://clarky.ai/api/v1/contacts/c_01HXYZ \
-H "Authorization: Bearer ck_live_example" \
-H "Content-Type: application/json" \
-d '{
"tags": ["vip", "newsletter"],
"deal_value": 30000
}'
{
"data": {
"id": "c_01HXYZ...",
"tags": ["vip", "newsletter"],
"deal_value": 30000,
"updated_at": "2026-04-29T18:50:00.000Z"
}
}
DELETE /api/v1/contacts/{id}
Returns 204 No Content with an empty body on success.
Example
curl -X DELETE https://clarky.ai/api/v1/contacts/c_01HXYZ \
-H "Authorization: Bearer ck_live_example"
Deletion is permanent — there’s no undo.
POST /api/v1/contacts/upsert
Insert or update up to 200 contacts in a single request. Each input contact is matched against existing contacts in this order:
- Primary email (if provided)
- Primary phone number (if no email match)
If a match is found, the existing contact is updated. If not, a new contact is created.
Body fields
| Field | Type | Required | Description |
|---|
bot_id | string | Yes | Agent to own newly created contacts |
contacts | array | Yes | Array of contact objects (same fields as Create). Max 200. |
Example
curl https://clarky.ai/api/v1/contacts/upsert \
-H "Authorization: Bearer ck_live_example" \
-H "Content-Type: application/json" \
-d '{
"bot_id": "b_01HDEF",
"contacts": [
{
"first_name": "Ada",
"emails": [{ "email": "ada@example.com", "is_primary": true }]
},
{
"first_name": "Grace",
"emails": [{ "email": "grace@example.com", "is_primary": true }]
}
]
}'
Response
{
"data": {
"created": [
{
"id": "c_01HNEW1...",
"first_name": "Grace",
"emails": [{ "email": "grace@example.com", "is_primary": true }]
}
],
"updated": [
{
"id": "c_01HXYZ...",
"first_name": "Ada",
"emails": [{ "email": "ada@example.com", "is_primary": true }]
}
],
"errors": []
}
}
Contacts that were newly inserted.
Contacts that matched an existing record and were updated.
Per-row failures as { index, message }. The numeric index is the position of the failing item in the input contacts array. The rest of the batch still succeeds.
Upsert counts as a single write against your rate limit regardless of how many contacts are in the batch — much more efficient than a loop of POST /contacts calls.