Reference
Leads
Leads: 9 operations (leads.list, leads.upsert, leads.get, leads.update, leads.delete, leads.tags.add, leads.tags.remove, leads.lookup, tags.list).
Every lead carries custom_fields, one entry per field the workspace defines, and GET /v1/leads filters on them with cf.<key> query keys. See Custom fields for reading, writing and filtering.
| Method | Path | Operation |
|---|---|---|
GET | /v1/leads | leads.list |
POST | /v1/leads | leads.upsert |
GET | /v1/leads/{lead_id} | leads.get |
PATCH | /v1/leads/{lead_id} | leads.update |
DELETE | /v1/leads/{lead_id} | leads.delete |
POST | /v1/leads/{lead_id}/tags | leads.tags.add |
DELETE | /v1/leads/{lead_id}/tags/{tag} | leads.tags.remove |
GET | /v1/leads/lookup | leads.lookup |
GET | /v1/tags | tags.list |
leads.list
GET/v1/leads
List the workspace's leads, newest first, with filters.
Keyset pagination: pass next_cursor as cursor with the same filters and order. order=updated_at_asc with updated_after is the incremental sync. Custom fields filter with query keys that start with cf.: cf.<key>=<text> (equals, trimmed, ignoring case), cf.<key>.contains=<text> (substring, ignoring case, every character literal), cf.<key>.present=true (has a non-blank value), cf.<key>.missing=true (no value or a blank one). Conditions AND together with each other and every other filter; at most 5; each key must be one the workspace defines (GET /v1/custom-fields), else 400 CUSTOM_FIELD_UNKNOWN_400; a value is at most 500 characters.
| Operation id | leads.list |
| Scopes | leads:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | no | 1 to 200, default 50 |
cursor | string | no | 1 to 2048 characters |
status | "new" | "contacted" | "replied" | "converted" | "not_interested" | "not_found" | no | |
tag | string | no | 1 to 100 characters |
niche | string | no | 1 to 200 characters |
folder_id | string | no | A folder id, or none for leads in no folder.. 1 to 200 characters |
search | string | no | Case-insensitive match on name, handles and notes.. 1 to 200 characters |
external_id | string | no | 1 to 255 characters |
ig_handle | string | no | Matched case-insensitively, a leading @ ignored.. 1 to 100 characters |
created_after | date-time | no | |
created_before | date-time | no | |
updated_after | date-time | no | |
exclude_inbound | boolean | no | |
campaign_id | string | no | Leads enrolled in this campaign.. 1 to 200 characters |
enrollment | "any" | "none" | no | Leads in at least one campaign (any) or in none. |
order | "created_at" | "updated_at" | "updated_at_asc" | no | default "created_at" |
cf.{key} | string | no |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
data | object[] | yes | |
has_more | boolean | yes | |
next_cursor | string | null | yes |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `CUSTOM_FIELD_UNKNOWN_400` | A cf.<key> condition names a key this workspace has not defined. |
| 404 | `CAMPAIGN_NOT_FOUND_404` | campaign_id names no campaign of this workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/leads" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"workspace_id": {
"type": "string"
},
"name": {
"type": "string"
},
"first_name": {
"type": [
"string",
"null"
]
},
"last_name": {
"type": [
"string",
"null"
]
},
"ig_handle": {
"type": [
"string",
"null"
]
},
"fb_handle": {
"type": [
"string",
"null"
]
},
"profile_url": {
"type": [
"string",
"null"
]
},
"niche": {
"type": [
"string",
"null"
]
},
"followers": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"status": {
"type": "string",
"enum": [
"new",
"contacted",
"replied",
"converted",
"not_interested",
"not_found"
]
},
"notes": {
"type": [
"string",
"null"
]
},
"email": {
"type": [
"string",
"null"
]
},
"phone": {
"type": [
"string",
"null"
]
},
"website": {
"type": [
"string",
"null"
]
},
"bio": {
"type": [
"string",
"null"
]
},
"company_name": {
"type": [
"string",
"null"
]
},
"last_contacted_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
{
"type": "null"
}
]
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"folder_id": {
"type": [
"string",
"null"
]
},
"custom_fields": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": [
"string",
"null"
]
},
"description": "Every custom field the workspace defines, in its order, null when the lead has no value for it; then any other key stored on the lead, as stored (an integrations key may write keys the workspace never defined)."
},
"external_id": {
"type": [
"string",
"null"
]
},
"assigned_rep_id": {
"type": [
"string",
"null"
]
},
"is_inbound": {
"type": "boolean"
},
"icp_verdict": {
"type": [
"string",
"null"
]
},
"setter_stage": {
"description": "List only: the newest thread's stage, when the key holds conversations:read and may see that thread's rep; null otherwise, and null when the plan does not include the AI Setter.",
"type": [
"string",
"null"
]
},
"setter_stall_reason": {
"description": "List only, under the same condition as setter_stage; null when the plan does not include the AI Setter.",
"type": [
"string",
"null"
]
},
"campaign": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"id",
"name",
"count"
],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "List only: the campaign that matters (a live enrollment first, then the newest) and how many the lead is in."
},
"created_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
"updated_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
}
},
"required": [
"id",
"workspace_id",
"name",
"first_name",
"last_name",
"ig_handle",
"fb_handle",
"profile_url",
"niche",
"followers",
"status",
"notes",
"email",
"phone",
"website",
"bio",
"company_name",
"last_contacted_at",
"tags",
"folder_id",
"custom_fields",
"external_id",
"assigned_rep_id",
"is_inbound",
"icp_verdict",
"setter_stage",
"setter_stall_reason",
"campaign",
"created_at",
"updated_at"
],
"additionalProperties": false
}
},
"has_more": {
"type": "boolean"
},
"next_cursor": {
"type": [
"string",
"null"
]
}
},
"required": [
"data",
"has_more",
"next_cursor"
],
"additionalProperties": false
}leads.upsert
POST/v1/leads
Create or update one lead, or a batch of up to 100.
Matches on external_id, then the Instagram handle. on_conflict decides what a match does: merge (default), skip, or error (409 LEAD_EXISTS_409, a create-only call). A batch runs one lead per transaction and reports each item in place.
| Operation id | leads.upsert |
| Scopes | leads:write |
| Rate class | `write`, plus leads_created_day |
| Idempotency | `Idempotency-Key` accepted |
| Keys | Developer keys and Clay compatible keys |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
custom_fields | any | no | { key: value } of the workspace's custom fields. |
email | any | no | |
external_id | any | no | |
fb_handle | any | no | |
first_name | any | no | |
folder | any | no | Folder NAME, created when missing. |
followers | any | no | A number, or a numeric string. |
ig_handle | any | no | Required for every lead: the matching key. |
last_name | any | no | |
leads | any | no | A batch: an array of 1 to 100 lead objects. Omit for one lead. |
merge | any | no | fill_empty (default) or overwrite. |
name | any | no | |
niche | any | no | |
notes | any | no | |
on_conflict | "merge" | "skip" | "error" | no | |
phone | any | no | |
profile_url | any | no | |
tags | any | no | An array of tags or one comma-separated string, at most 20. |
Response 200
JSON of type object.
Errors
| Status | Code | When |
|---|---|---|
| 400 | `CUSTOM_FIELD_UNKNOWN_400` | custom_fields names a key this workspace has not defined. Create it with POST /v1/custom-fields first. |
| 400 | `LEADS_BATCH_TOO_LARGE_400` | The batch holds more than 100 leads. |
| 409 | `LEAD_AMBIGUOUS_409` | More than one lead in this workspace has that Instagram handle. |
| 409 | `LEAD_EXISTS_409` | on_conflict is error and the lead already exists. |
| 429 | `LEADS_DAILY_LIMIT_429` | The organization reached its daily limit of leads created through the API. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X POST "https://api.dmhero.ai/v1/leads" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"ig_handle": "jane.doe",
"first_name": "Jane",
"last_name": "Doe",
"external_id": "crm-1042",
"tags": [
"webinar"
]
}'JSON Schema
{
"type": "object",
"properties": {
"ig_handle": {
"description": "Required for every lead: the matching key."
},
"name": {},
"first_name": {},
"last_name": {},
"fb_handle": {},
"profile_url": {},
"niche": {},
"followers": {
"description": "A number, or a numeric string."
},
"notes": {},
"tags": {
"description": "An array of tags or one comma-separated string, at most 20."
},
"folder": {
"description": "Folder NAME, created when missing."
},
"custom_fields": {
"description": "{ key: value } of the workspace's custom fields."
},
"external_id": {},
"email": {},
"phone": {},
"merge": {
"description": "fill_empty (default) or overwrite."
},
"leads": {
"description": "A batch: an array of 1 to 100 lead objects. Omit for one lead."
},
"on_conflict": {
"type": "string",
"enum": [
"merge",
"skip",
"error"
]
}
}
}{
"anyOf": [
{
"type": "object",
"properties": {
"lead_id": {
"type": "string"
},
"result": {
"type": "string",
"enum": [
"created",
"updated",
"unchanged",
"skipped"
]
},
"updated_fields": {
"type": "array",
"items": {
"type": "string"
}
},
"lead_status": {
"type": "string"
}
},
"required": [
"lead_id",
"result",
"updated_fields",
"lead_status"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"lead_id": {
"type": "string"
},
"result": {
"type": "string",
"enum": [
"created",
"updated",
"unchanged",
"skipped"
]
},
"updated_fields": {
"type": "array",
"items": {
"type": "string"
}
},
"lead_status": {
"type": "string"
},
"index": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"lead_id",
"result",
"updated_fields",
"lead_status",
"index"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"index": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"error": {
"type": "string"
},
"message": {
"type": "string"
},
"code": {
"type": "string"
},
"lead_id": {
"type": "string"
},
"fields": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
}
}
},
"required": [
"index",
"error",
"message",
"code"
],
"additionalProperties": false
}
]
}
}
},
"required": [
"results"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"replayed": {
"type": "boolean",
"const": true
},
"status": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"ids": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
}
}
},
"required": [
"replayed",
"status",
"ids"
],
"additionalProperties": false
}
]
}leads.get
GET/v1/leads/{lead_id}
One lead. The ETag header is the version PATCH accepts as If-Match.
| Operation id | leads.get |
| Scopes | leads:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
lead_id | string | yes | The lead id.. 1 to 200 characters |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
assigned_rep_id | string | null | yes | |
bio | string | null | yes | |
campaign | object | null | yes | List only: the campaign that matters (a live enrollment first, then the newest) and how many the lead is in. |
company_name | string | null | yes | |
created_at | date-time | yes | |
custom_fields | object | yes | Every custom field the workspace defines, in its order, null when the lead has no value for it; then any other key stored on the lead, as stored (an integrations key may write keys the workspace never defined). |
email | string | null | yes | |
external_id | string | null | yes | |
fb_handle | string | null | yes | |
first_name | string | null | yes | |
folder_id | string | null | yes | |
followers | integer | null | yes | |
icp_verdict | string | null | yes | |
id | string | yes | |
ig_handle | string | null | yes | |
is_inbound | boolean | yes | |
last_contacted_at | date-time | null | yes | |
last_name | string | null | yes | |
name | string | yes | |
niche | string | null | yes | |
notes | string | null | yes | |
phone | string | null | yes | |
profile_url | string | null | yes | |
setter_stage | string | null | yes | List only: the newest thread's stage, when the key holds conversations:read and may see that thread's rep; null otherwise, and null when the plan does not include the AI Setter. |
setter_stall_reason | string | null | yes | List only, under the same condition as setter_stage; null when the plan does not include the AI Setter. |
status | "new" | "contacted" | "replied" | "converted" | "not_interested" | "not_found" | yes | |
tags | string[] | yes | |
updated_at | date-time | yes | |
website | string | null | yes | |
workspace_id | string | yes |
Errors
| Status | Code | When |
|---|---|---|
| 404 | `LEAD_NOT_FOUND_404` | No lead with this id exists in this workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/leads/string" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"workspace_id": {
"type": "string"
},
"name": {
"type": "string"
},
"first_name": {
"type": [
"string",
"null"
]
},
"last_name": {
"type": [
"string",
"null"
]
},
"ig_handle": {
"type": [
"string",
"null"
]
},
"fb_handle": {
"type": [
"string",
"null"
]
},
"profile_url": {
"type": [
"string",
"null"
]
},
"niche": {
"type": [
"string",
"null"
]
},
"followers": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"status": {
"type": "string",
"enum": [
"new",
"contacted",
"replied",
"converted",
"not_interested",
"not_found"
]
},
"notes": {
"type": [
"string",
"null"
]
},
"email": {
"type": [
"string",
"null"
]
},
"phone": {
"type": [
"string",
"null"
]
},
"website": {
"type": [
"string",
"null"
]
},
"bio": {
"type": [
"string",
"null"
]
},
"company_name": {
"type": [
"string",
"null"
]
},
"last_contacted_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
{
"type": "null"
}
]
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"folder_id": {
"type": [
"string",
"null"
]
},
"custom_fields": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": [
"string",
"null"
]
},
"description": "Every custom field the workspace defines, in its order, null when the lead has no value for it; then any other key stored on the lead, as stored (an integrations key may write keys the workspace never defined)."
},
"external_id": {
"type": [
"string",
"null"
]
},
"assigned_rep_id": {
"type": [
"string",
"null"
]
},
"is_inbound": {
"type": "boolean"
},
"icp_verdict": {
"type": [
"string",
"null"
]
},
"setter_stage": {
"description": "List only: the newest thread's stage, when the key holds conversations:read and may see that thread's rep; null otherwise, and null when the plan does not include the AI Setter.",
"type": [
"string",
"null"
]
},
"setter_stall_reason": {
"description": "List only, under the same condition as setter_stage; null when the plan does not include the AI Setter.",
"type": [
"string",
"null"
]
},
"campaign": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"id",
"name",
"count"
],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "List only: the campaign that matters (a live enrollment first, then the newest) and how many the lead is in."
},
"created_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
"updated_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
}
},
"required": [
"id",
"workspace_id",
"name",
"first_name",
"last_name",
"ig_handle",
"fb_handle",
"profile_url",
"niche",
"followers",
"status",
"notes",
"email",
"phone",
"website",
"bio",
"company_name",
"last_contacted_at",
"tags",
"folder_id",
"custom_fields",
"external_id",
"assigned_rep_id",
"is_inbound",
"icp_verdict",
"setter_stage",
"setter_stall_reason",
"campaign",
"created_at",
"updated_at"
],
"additionalProperties": false
}leads.update
PATCH/v1/leads/{lead_id}
Change a lead's fields. Send If-Match with the ETag you read to refuse a concurrent change.
| Operation id | leads.update |
| Scopes | leads:write |
| Rate class | `write` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
lead_id | string | yes | The lead id.. 1 to 200 characters |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
assigned_rep_id | string | null | no | A rep this key may use, or null. |
custom_fields | object | no | { key: value | null }; null removes the value. Keys the request does not name are left alone. |
email | string | null | no | |
fb_handle | string | null | no | |
folder_id | string | null | no | null leaves the lead in no folder. |
followers | integer | null | no | |
ig_handle | string | null | no | |
name | string | no | |
niche | string | null | no | |
notes | string | null | no | |
phone | string | null | no | |
profile_url | string | null | no | |
status | "new" | "contacted" | "replied" | "converted" | "not_interested" | "not_found" | no |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
assigned_rep_id | string | null | yes | |
bio | string | null | yes | |
campaign | object | null | yes | List only: the campaign that matters (a live enrollment first, then the newest) and how many the lead is in. |
company_name | string | null | yes | |
created_at | date-time | yes | |
custom_fields | object | yes | Every custom field the workspace defines, in its order, null when the lead has no value for it; then any other key stored on the lead, as stored (an integrations key may write keys the workspace never defined). |
email | string | null | yes | |
external_id | string | null | yes | |
fb_handle | string | null | yes | |
first_name | string | null | yes | |
folder_id | string | null | yes | |
followers | integer | null | yes | |
icp_verdict | string | null | yes | |
id | string | yes | |
ig_handle | string | null | yes | |
is_inbound | boolean | yes | |
last_contacted_at | date-time | null | yes | |
last_name | string | null | yes | |
name | string | yes | |
niche | string | null | yes | |
notes | string | null | yes | |
phone | string | null | yes | |
profile_url | string | null | yes | |
setter_stage | string | null | yes | List only: the newest thread's stage, when the key holds conversations:read and may see that thread's rep; null otherwise, and null when the plan does not include the AI Setter. |
setter_stall_reason | string | null | yes | List only, under the same condition as setter_stage; null when the plan does not include the AI Setter. |
status | "new" | "contacted" | "replied" | "converted" | "not_interested" | "not_found" | yes | |
tags | string[] | yes | |
updated_at | date-time | yes | |
website | string | null | yes | |
workspace_id | string | yes |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `CUSTOM_FIELD_UNKNOWN_400` | custom_fields names a key this workspace has not defined. Create it with POST /v1/custom-fields first. |
| 404 | `FOLDER_NOT_FOUND_404` | No folder with this id exists in this workspace. |
| 404 | `LEAD_NOT_FOUND_404` | No lead with this id exists in this workspace. |
| 404 | `REP_NOT_FOUND_404` | No rep with this id or username that this API key may use. |
| 412 | `LEAD_PRECONDITION_FAILED_412` | If-Match does not match: the lead changed since you read it. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X PATCH "https://api.dmhero.ai/v1/leads/string" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"ig_handle": "string",
"fb_handle": "string",
"profile_url": "string",
"niche": "string",
"followers": 0,
"notes": "string",
"status": "new",
"email": "string",
"phone": "string",
"assigned_rep_id": "string",
"folder_id": "string",
"custom_fields": {}
}'JSON Schema
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"ig_handle": {
"type": [
"string",
"null"
]
},
"fb_handle": {
"type": [
"string",
"null"
]
},
"profile_url": {
"type": [
"string",
"null"
]
},
"niche": {
"type": [
"string",
"null"
]
},
"followers": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 2147483647
},
{
"type": "null"
}
]
},
"notes": {
"type": [
"string",
"null"
]
},
"status": {
"type": "string",
"enum": [
"new",
"contacted",
"replied",
"converted",
"not_interested",
"not_found"
]
},
"email": {
"type": [
"string",
"null"
]
},
"phone": {
"type": [
"string",
"null"
]
},
"assigned_rep_id": {
"description": "A rep this key may use, or null.",
"anyOf": [
{
"type": "string",
"minLength": 1,
"maxLength": 200
},
{
"type": "null"
}
]
},
"folder_id": {
"description": "null leaves the lead in no folder.",
"anyOf": [
{
"type": "string",
"minLength": 1,
"maxLength": 200
},
{
"type": "null"
}
]
},
"custom_fields": {
"description": "{ key: value | null }; null removes the value. Keys the request does not name are left alone.",
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": [
"string",
"null"
]
}
}
}
}{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"workspace_id": {
"type": "string"
},
"name": {
"type": "string"
},
"first_name": {
"type": [
"string",
"null"
]
},
"last_name": {
"type": [
"string",
"null"
]
},
"ig_handle": {
"type": [
"string",
"null"
]
},
"fb_handle": {
"type": [
"string",
"null"
]
},
"profile_url": {
"type": [
"string",
"null"
]
},
"niche": {
"type": [
"string",
"null"
]
},
"followers": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"status": {
"type": "string",
"enum": [
"new",
"contacted",
"replied",
"converted",
"not_interested",
"not_found"
]
},
"notes": {
"type": [
"string",
"null"
]
},
"email": {
"type": [
"string",
"null"
]
},
"phone": {
"type": [
"string",
"null"
]
},
"website": {
"type": [
"string",
"null"
]
},
"bio": {
"type": [
"string",
"null"
]
},
"company_name": {
"type": [
"string",
"null"
]
},
"last_contacted_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
{
"type": "null"
}
]
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"folder_id": {
"type": [
"string",
"null"
]
},
"custom_fields": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": [
"string",
"null"
]
},
"description": "Every custom field the workspace defines, in its order, null when the lead has no value for it; then any other key stored on the lead, as stored (an integrations key may write keys the workspace never defined)."
},
"external_id": {
"type": [
"string",
"null"
]
},
"assigned_rep_id": {
"type": [
"string",
"null"
]
},
"is_inbound": {
"type": "boolean"
},
"icp_verdict": {
"type": [
"string",
"null"
]
},
"setter_stage": {
"description": "List only: the newest thread's stage, when the key holds conversations:read and may see that thread's rep; null otherwise, and null when the plan does not include the AI Setter.",
"type": [
"string",
"null"
]
},
"setter_stall_reason": {
"description": "List only, under the same condition as setter_stage; null when the plan does not include the AI Setter.",
"type": [
"string",
"null"
]
},
"campaign": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"id",
"name",
"count"
],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "List only: the campaign that matters (a live enrollment first, then the newest) and how many the lead is in."
},
"created_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
"updated_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
}
},
"required": [
"id",
"workspace_id",
"name",
"first_name",
"last_name",
"ig_handle",
"fb_handle",
"profile_url",
"niche",
"followers",
"status",
"notes",
"email",
"phone",
"website",
"bio",
"company_name",
"last_contacted_at",
"tags",
"folder_id",
"custom_fields",
"external_id",
"assigned_rep_id",
"is_inbound",
"icp_verdict",
"setter_stage",
"setter_stall_reason",
"campaign",
"created_at",
"updated_at"
],
"additionalProperties": false
}leads.delete
DELETE/v1/leads/{lead_id}
Delete a lead, its tags and its enrollments.
| Operation id | leads.delete |
| Scopes | leads:delete |
| Rate class | `write` |
| Idempotency | Not applicable |
| Keys | Developer keys |
| Destructive | Yes: it removes or stops something that cannot be restored by repeating the call |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
lead_id | string | yes | The lead id.. 1 to 200 characters |
Response 204
No body.
Errors
| Status | Code | When |
|---|---|---|
| 404 | `LEAD_NOT_FOUND_404` | No lead with this id exists in this workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X DELETE "https://api.dmhero.ai/v1/leads/string" \
-H "Authorization: Bearer $DMHERO_API_KEY"leads.tags.add
POST/v1/leads/{lead_id}/tags
Add tags to a lead. Tags it already has are left as they are.
| Operation id | leads.tags.add |
| Scopes | leads:write |
| Rate class | `write` |
| Idempotency | `Idempotency-Key` accepted |
| Keys | Developer keys |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
lead_id | string | yes | The lead id.. 1 to 200 characters |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
tags | string[] | yes | 1 to 20 items |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
lead_id | string | yes | |
tags | string[] | yes |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `TAG_INVALID_400` | A tag is empty or longer than the tag limit. |
| 404 | `LEAD_NOT_FOUND_404` | No lead with this id exists in this workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X POST "https://api.dmhero.ai/v1/leads/string/tags" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"tags": [
"string"
]
}'JSON Schema
{
"type": "object",
"properties": {
"tags": {
"minItems": 1,
"maxItems": 20,
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"tags"
]
}{
"type": "object",
"properties": {
"lead_id": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"lead_id",
"tags"
],
"additionalProperties": false
}leads.tags.remove
DELETE/v1/leads/{lead_id}/tags/{tag}
Remove one tag from a lead (URL-encode the tag). Removing a tag the lead does not have is not an error.
| Operation id | leads.tags.remove |
| Scopes | leads:write |
| Rate class | `write` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
lead_id | string | yes | The lead id.. 1 to 200 characters |
tag | string | yes | 1 to 200 characters |
Response 204
No body.
Errors
| Status | Code | When |
|---|---|---|
| 400 | `TAG_INVALID_400` | A tag is empty or longer than the tag limit. |
| 404 | `LEAD_NOT_FOUND_404` | No lead with this id exists in this workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X DELETE "https://api.dmhero.ai/v1/leads/string/tags/string" \
-H "Authorization: Bearer $DMHERO_API_KEY"leads.lookup
GET/v1/leads/lookup
Where the lead with this Instagram handle stands: status, setter stage, tags, campaign.
| Operation id | leads.lookup |
| Scopes | leads:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys and Clay compatible keys |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
ig_handle | any | no | Required. At most 30 characters, a leading @ ignored. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
campaign_id | string | null | yes | |
campaign_status | string | null | yes | |
current_step | integer | null | yes | |
last_contacted_at | date-time | null | yes | |
lead_id | string | yes | |
setter_stage | string | null | yes | Null when the plan does not include the AI Setter. |
setter_stall_reason | string | null | yes | Null when the plan does not include the AI Setter. |
status | string | yes | |
tags | string[] | yes |
Errors
| Status | Code | When |
|---|---|---|
| 404 | `LEAD_NOT_FOUND_404` | No lead with that Instagram handle in this API key's workspace. |
| 409 | `LEAD_AMBIGUOUS_409` | More than one lead in this workspace has that Instagram handle. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/leads/lookup?ig_handle=jane.doe" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"lead_id": {
"type": "string"
},
"status": {
"type": "string"
},
"setter_stage": {
"description": "Null when the plan does not include the AI Setter.",
"type": [
"string",
"null"
]
},
"setter_stall_reason": {
"description": "Null when the plan does not include the AI Setter.",
"type": [
"string",
"null"
]
},
"last_contacted_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
{
"type": "null"
}
]
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"campaign_id": {
"type": [
"string",
"null"
]
},
"campaign_status": {
"type": [
"string",
"null"
]
},
"current_step": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
}
},
"required": [
"lead_id",
"status",
"setter_stage",
"setter_stall_reason",
"last_contacted_at",
"tags",
"campaign_id",
"campaign_status",
"current_step"
],
"additionalProperties": false
}tags.list
GET/v1/tags
Every tag used on the workspace's leads, alphabetical.
| Operation id | tags.list |
| Scopes | leads:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
data | string[] | yes |
Errors
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/tags" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"data"
],
"additionalProperties": false
}