People and lists
How to keep the people you know, group them in lists, look people up, find a work email, and keep the wrong people from ever being contacted.
This page covers the people a workspace knows, the lists that group them, looking people up, finding a work email, and the do-not-contact list.
A person is someone on LinkedIn that the workspace knows about. A list is a named group of people. Lists are what you point a campaign or a scoring run at.
The main calls
Add people
POST /people adds up to 500 people by LinkedIn profile link. People the workspace already knows are matched, not duplicated. Send list to also put them on a list.
curl https://api.done.com/v1/people \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: 5e0a8c93-2b71-4d4f-9a16-c8b3e7d20f4a" \
-H "Content-Type: application/json" \
-d '{
"people": [
{ "linkedin_url": "https://www.linkedin.com/in/ana-lima", "first_name": "Ana", "last_name": "Lima" },
{ "linkedin_url": "https://www.linkedin.com/in/tomas-reyes" }
],
"list": "lst_4LmZ8nQw"
}'This only saves people. It does not read their profiles, score them or message them. Links that are not a person's profile come back in refused, and the rest are still added. It is free.
Read people
GET /people lists the people the workspace knows, newest first. Filter by list, campaign, scout or min_fit. Filters combine: a person must match all you send. A person who has never been scored has no latest_fit, so min_fit leaves them out.
curl "https://api.done.com/v1/people?list=lst_4LmZ8nQw&min_fit=70" \
-H "Authorization: Bearer $DONE_API_KEY"GET /people/{id} returns one person: who they are, the lists and campaigns they are in, and their latest fit score. It never returns an email address. Use the email call for that.
Make and fill lists
# Make an empty list
curl https://api.done.com/v1/lists \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: 1c6f9b28-7d34-4e51-8b0a-3a9d52e6c7f1" \
-H "Content-Type: application/json" \
-d '{ "name": "UK finance leaders" }'
# Put people on it
curl https://api.done.com/v1/lists/lst_4LmZ8nQw/people \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "people": [ { "person": "per_9aQw1XyZ" }, { "linkedin_url": "https://www.linkedin.com/in/tomas-reyes" } ] }'POST /lists/{id}/peopleputs up to 500 people on a list, bypersonid or bylinkedin_url. People already on the list are counted inalready_on_listand left alone.POST /lists/{id}/people/removetakes up to 500 people off a list, by person id. They stay in the workspace and on any other list.PATCH /lists/{id}renames a list.DELETE /lists/{id}deletes it. The people stay in the workspace, and a campaign that used the list keeps the people it already took in.GET /listsandGET /lists/{id}read lists.
Search and look up (full plan)
These two calls read LinkedIn on your behalf. They are not part of the API-only plan, which sells results and never raw LinkedIn data.
POST /people/search reads one page of LinkedIn people search results, about 25 people. Search by titles, companies, places and industries, or send a Sales Navigator people search link. Ask for page 2, 3 and so on to read more. Nothing is saved unless you send save_to_list.
curl https://api.done.com/v1/people/search \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: 8a24d7e1-96c5-4b30-a7f8-12e5c0b94d63" \
-H "Content-Type: application/json" \
-d '{
"titles": ["CFO", "Finance Director"],
"places": ["United Kingdom"],
"industries": ["Fintech"],
"page": 1,
"save_to_list": "lst_4LmZ8nQw"
}'Results are not scored and not messaged. To see who fits, score them with POST /scores or POST /scoring_runs. For people who match a customer profile over time, create a scout instead.
POST /people/lookup reads one person's public LinkedIn profile and returns it cleaned up: name, headline, company, role, location, recent experience and a short summary of recent posts. Nothing is saved.
curl https://api.done.com/v1/people/lookup \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: e3f71a09-4c85-4d26-b1d7-6a0c9e82f5b4" \
-H "Content-Type: application/json" \
-d '{ "linkedin_url": "https://www.linkedin.com/in/ana-lima" }'Find a work email
POST /people/{id}/email looks for one person's work email address.
curl -X POST https://api.done.com/v1/people/per_9aQw1XyZ/email \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: 7b19e4c6-0d3a-4f82-95e1-a2c8d6f30b57"{
"object": "email_lookup",
"person": "per_9aQw1XyZ",
"email": "ana.lima@lumenpay.example",
"status": "found",
"confidence": "good",
"checked_at": "2026-10-23T09:50:00Z",
"credits": 0.7
}The answer is found or not_found. A found address carries a confidence of good, risky or unknown. done. never test-sends to the address.
Keep people from ever being contacted
The do-not-contact list holds the people, and the companies, that done. will never message.
curl https://api.done.com/v1/do_not_contact/people \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: 3d58b0f2-a649-4e17-8c93-5f1e7a2d84c0" \
-H "Content-Type: application/json" \
-d '{
"linkedin_url": "https://www.linkedin.com/in/ana-lima",
"name": "Ana Lima",
"company": "Lumen Pay",
"reason": "Asked us to stop"
}'| Call | What it does |
|---|---|
POST /do_not_contact/people | Never message this person. Also takes them out of any campaign still in progress, at once. taken_out_of_campaigns says how many were stopped. |
POST /do_not_contact/companies | Never message anyone at this company. Send the name, and the domain if you have it, which matches more reliably. |
POST /do_not_contact/import | Add up to 1,000 people in one call. Links already on the list are skipped. |
GET /do_not_contact/people and GET /do_not_contact/companies | List entries, newest first. The list never says who added an entry. |
DELETE /do_not_contact/people/{id} and DELETE /do_not_contact/companies/{id} | Take an entry off the list. |
What it costs
| Call | Cost |
|---|---|
| Add people, lists, do-not-contact, reads | free |
POST /people/search | about 1.4 a page |
POST /people/lookup | about 0.1 |
POST /people/{id}/email | about 0.7, only when an email is found for the first time |
Search pages also count against the plan's monthly search-page allowance. When it is used up, credits do not lift it: the 402 search_allowance_reached says when it resets. See Credits and costs.
Rules that apply
- Do-not-contact entries reach campaigns at once. Adding a person takes them out of campaigns that are still in progress. People whose campaign already finished are left as they were. Removing an entry later does not put anyone back into a campaign they were taken out of. It only lets campaigns that take people in from then on contact them.
- Emails are cached for 90 days. Answers, including
not_found, are kept for 90 days. Asking again within 90 days returns the same answer and costs nothing. You are charged only when an address is found for the first time. The workspace must still have at least 0.7 available when you ask, or the call is refused withinsufficient_credits. - A person is never returned with an email. Only the email call returns an address.
- Permissions. Search, lookup and email need
spend. Adding people, changing lists and the do-not-contact list needfull. Reading needsread. - Retries. Calls that add, search, look up or find an email take an
Idempotency-Key. See Safe retries.