Leads
Add leads in bulk (up to 1,000 per request), read, update and delete them, and read a lead's conversation.
List leads
Lists the leads in the API key's workspace, newest first, with pagination. Filter by exact email address to look up a single lead, or by campaign to list only the leads in one campaign. This is how a lead created through POST /leads is found again.
Parameters
- page integer in query
Page number (default: 1)
- limit integer in query
Page size (default: 20, maximum: 200)
- email string in query
Filter by exact email address
- campaignId integer in query
Filter by campaign ID
Responses
- 200 List of leads · ListLeadsResponse
- 400 Invalid query parameters · ErrorResponse
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 500 Failed to retrieve leads · ErrorFailedToRetrieveLeads
Fields in the 200 response
- hasMore booleanExample:
true - leads array of LeadResponse
15 fields inside leads
- company stringExample:
Acme Corp - createdAt stringExample:
2024-01-15T10:30:00Z - customVariables map of object
CustomVariables are the lead's merge tags beyond the named fields.
- email stringExample:
john.doe@example.com - firstName stringExample:
John - id integerExample:
123 - lastName stringExample:
Doe - linkedin stringExample:
https://linkedin.com/in/johndoe - meetingBookedAt string
MeetingBookedAt is when a meeting was explicitly marked as booked with this lead (see POST /leads/{id}/meeting) and null while no meeting is marked.
Example:2026-07-30T14:05:00Z - middleName stringExample:
A. - phone stringExample:
+1234567890 - tag string
Tag is the lead's engagement category (interested, not_interested, bounced, out_of_office, delivery_incomplete, meeting_booked) and null while the lead has never been categorized.
Example:interested - title stringExample:
Software Engineer - updatedAt stringExample:
2024-01-15T10:30:00Z - website stringExample:
https://example.com
- limit integerExample:
20 - page integerExample:
1 - total integerExample:
42
Request
curl -X GET "https://api.emailchaser.com/r/leads" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"hasMore": true,
"leads": [
{
"company": "Acme Corp",
"createdAt": "2024-01-15T10:30:00Z",
"customVariables": {},
"email": "john.doe@example.com",
"firstName": "John",
"id": 123,
"lastName": "Doe",
"linkedin": "https://linkedin.com/in/johndoe",
"meetingBookedAt": "2026-07-30T14:05:00Z",
"middleName": "A.",
"phone": "+1234567890",
"tag": "interested",
"title": "Software Engineer",
"updatedAt": "2024-01-15T10:30:00Z",
"website": "https://example.com"
}
],
"limit": 20,
"page": 1,
"total": 42
}Create or update leads in bulk
Creates or updates up to 1,000 leads in one request. Leads are matched by email within the workspace. If a lead with that email already exists, it is updated, and every named field you leave out is cleared, so send the full lead each time. An update also clears the lead's city, country, industry and company description, which the API cannot set. middleName is only saved when a lead is created. customVariables, when sent, replaces the lead's variables; leave it out to keep them. Every lead needs a valid email: one invalid lead fails the whole request with 400, and nothing is saved. To add the leads to a campaign, pass campaignId at the top level of the request body, not inside a lead. The campaign must have at least one email account attached (POST /campaigns/{id}/sender-emails). If it has none, the leads are saved and added to the campaign, but the call fails with 500; attach an account and send the same request again. count in the response is the number of leads you sent, not the number created. Any attribute outside the named fields can be sent in customVariables and becomes a merge tag usable in email copy. PUT /leads is an alias for this endpoint and behaves identically.
Request bodyJSON · CreateOrUpdateLeadsRequest
- campaignId integer
- At least 1 item. At most 1,000 items
10 fields inside leads
- company string
- customVariables map of object
CustomVariables holds any attribute the eight named fields do not cover, for example the page a visitor landed on. Each key becomes a merge tag usable in email copy as {key}. Keys are matched case-insensitively with spaces treated as underscores, so "Page Visited" and "page_visited" are the same tag. Values are stored as given; non-string values are rendered with their JSON representation at send time.
- email string required
- firstName string
- lastName string
- linkedin string
- middleName string
Saved when the lead is created. Not changed when a lead with this email already exists.
- phone string
- title string
- website string
Responses
- 201 Leads processed successfully · CreateLeadsResponse
- 400 Invalid request body, an invalid email, or no leads provided · ErrorInvalidRequest
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 422 The new leads would go over the plan's contact limit · ErrorResponse
- 500 Failed to save the leads, or the campaign has no email account attached · ErrorFailedToCreateLeads
Fields in the 201 response
- count integerExample:
5 - leads array of CreatedLead
2 fields inside leads
- email stringExample:
john.doe@example.com - id integerExample:
123
- message stringExample:
leads processed successfully
Request
curl -X POST "https://api.emailchaser.com/r/leads" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaignId": 123,
"leads": [
{
"company": "Acme",
"customVariables": {},
"email": "jane@acme.com",
"firstName": "Jane",
"lastName": "Doe",
"linkedin": "https://www.linkedin.com/in/janedoe",
"middleName": "",
"phone": "+1 415 555 0100",
"title": "Head of Sales",
"website": "https://acme.com"
}
]
}'Response
{
"count": 5,
"leads": [
{
"email": "john.doe@example.com",
"id": 123
}
],
"message": "leads processed successfully"
}Get a lead by ID
Retrieves one lead. The lead comes back as a flat object, not wrapped in a "lead" key. It has no middleName; GET /leads includes it.
Parameters
- id integer required in path
Lead ID
Responses
- 200 Lead details · GetLeadResponse
- 400 Invalid lead ID · ErrorInvalidLeadID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 403 Forbidden - lead does not belong to your space · ErrorForbidden
- 404 Lead not found · ErrorNotFound
Fields in the 200 response
- company stringExample:
Acme Corp - createdAt stringExample:
2024-01-15T10:30:00Z - customVariables map of object
CustomVariables are the lead's merge tags beyond the named fields. Always present; null or empty when the lead has none.
- email stringExample:
john.doe@example.com - firstName stringExample:
John - id integerExample:
123 - lastName stringExample:
Doe - linkedin stringExample:
https://linkedin.com/in/johndoe - meetingBookedAt string
MeetingBookedAt is when a meeting was explicitly marked as booked with this lead (see POST /leads/{id}/meeting) and null while no meeting is marked.
Example:2026-07-30T14:05:00Z - phone stringExample:
+1234567890 - tag string
Tag is the lead's engagement category (interested, not_interested, bounced, out_of_office, delivery_incomplete, meeting_booked) and null while the lead has never been categorized.
Example:interested - title stringExample:
Software Engineer - updatedAt stringExample:
2024-01-15T10:30:00Z - website stringExample:
https://example.com
Request
curl -X GET "https://api.emailchaser.com/r/leads/123" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"company": "Acme Corp",
"createdAt": "2024-01-15T10:30:00Z",
"customVariables": {},
"email": "john.doe@example.com",
"firstName": "John",
"id": 123,
"lastName": "Doe",
"linkedin": "https://linkedin.com/in/johndoe",
"meetingBookedAt": "2026-07-30T14:05:00Z",
"phone": "+1234567890",
"tag": "interested",
"title": "Software Engineer",
"updatedAt": "2024-01-15T10:30:00Z",
"website": "https://example.com"
}Update a lead by ID
Updates one lead. What happens depends on whether the lead is in a campaign. For a lead in no campaign, only the fields you send are changed, and customVariables, when sent, replaces the whole set. For a lead in a campaign, the lead is saved again from your request: every named field you leave out is cleared, so send the full lead each time. This also clears the lead's city, country, industry and company description, which the API cannot set. customVariables is kept if you leave it out. Sending a different email does not change this lead: it creates a lead with the new email in the same campaign, or overwrites the lead that already has that email, and this lead stays as it was. middleName is accepted but never saved. The response holds only the lead's id, email, firstName and lastName, plus customVariables for a lead in no campaign. Read the full lead with GET /leads/{id}.
Parameters
- id integer required in path
Lead ID
Request bodyJSON · UpdateLeadRequest
- company string
- customVariables map of object
CustomVariables replaces the lead's whole custom variable map when provided. Omit it to leave the existing variables untouched.
- email string
For a lead in a campaign, a different email does not change this lead: it creates a lead with the new email in the same campaign, or overwrites the lead that already has it.
- firstName string
- lastName string
- linkedin string
- middleName string
Accepted but never saved by this endpoint.
- phone string
- title string
- website string
Responses
- 200 Lead updated successfully · UpdateLeadResponse
- 400 Invalid lead ID or request body · ErrorInvalidLeadID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 403 Forbidden - lead does not belong to your space · ErrorForbidden
- 404 Lead not found · ErrorNotFound
- 500 Failed to update lead · ErrorFailedToUpdateLead
Fields in the 200 response
- lead UpdatedLead
5 fields inside lead
- customVariables map of object
CustomVariables is returned only for a lead in no campaign.
- email stringExample:
john.doe@example.com - firstName stringExample:
John - id integerExample:
123 - lastName stringExample:
Doe
- message stringExample:
lead updated successfully
Request
curl -X PUT "https://api.emailchaser.com/r/leads/123" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"company": "Acme",
"customVariables": {},
"email": "jane@acme.com",
"firstName": "Jane",
"lastName": "Doe",
"linkedin": "https://www.linkedin.com/in/janedoe",
"middleName": "",
"phone": "+1 415 555 0100",
"title": "Head of Sales",
"website": "https://acme.com"
}'Response
{
"lead": {
"customVariables": {},
"email": "john.doe@example.com",
"firstName": "John",
"id": 123,
"lastName": "Doe"
},
"message": "lead updated successfully"
}Delete a lead by ID
Deletes a lead and all associated unsent emails. If the lead is associated with campaigns, it will be removed from those campaigns first.
Parameters
- id integer required in path
Lead ID
Responses
- 200 Lead deleted successfully · DeleteLeadResponse
- 400 Invalid lead ID · ErrorInvalidLeadID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 403 Forbidden - lead does not belong to your space · ErrorForbidden
- 404 Lead not found · ErrorNotFound
- 500 Failed to delete lead · ErrorFailedToDeleteLead
Fields in the 200 response
- id integerExample:
123 - message stringExample:
lead deleted successfully
Request
curl -X DELETE "https://api.emailchaser.com/r/leads/123" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"id": 123,
"message": "lead deleted successfully"
}Set or correct a lead's category
Sets the lead's category (tag), typically to correct an AI misclassification of a reply. Validated against the category enum: interested, not_interested, bounced, out_of_office, delivery_incomplete, meeting_booked. Setting meeting_booked behaves exactly like POST /leads/{id}/meeting: it records meetingBookedAt when unset and keeps an existing one, because a meeting is an explicit mark set by you or your agent, never inferred by the system. A real category change fires the LeadCategoryUpdate webhook; setting the value the lead already has is a no-op. Changing the category away from meeting_booked does NOT clear the booked-meeting mark - use DELETE /leads/{id}/meeting for that.
Parameters
- id integer required in path
Lead ID
Request bodyJSON · UpdateLeadCategoryRequest
- category string required
Category must be one of the lead category values: interested, not_interested, bounced, out_of_office, delivery_incomplete, meeting_booked.
Example:interested
Responses
- 200 Lead category updated · UpdateLeadCategoryResponse
- 400 Invalid lead ID, request body, or category · ErrorInvalidCategory
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Lead not found · ErrorNotFound
- 500 Failed to update lead category · ErrorResponse
Fields in the 200 response
- lead LeadCategoryState
3 fields inside lead
- id integerExample:
123 - meetingBookedAt string
MeetingBookedAt is when the meeting was marked as booked and null while no meeting is marked.
Example:2026-07-30T14:05:00Z - tag string
Tag is the lead's engagement category and null while the lead has never been categorized.
Example:meeting_booked
- message stringExample:
lead category updated successfully
Request
curl -X PUT "https://api.emailchaser.com/r/leads/123/category" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"category": "interested"
}'Response
{
"lead": {
"id": 123,
"meetingBookedAt": "2026-07-30T14:05:00Z",
"tag": "meeting_booked"
},
"message": "lead category updated successfully"
}Generated from the Emailchaser API's own OpenAPI definition, so it always matches the running API.