Quickstart
Make a key, check it, score one person, score a list, and hear when it is finished.
This page takes you from no key to a scored list in five short steps. Every example uses curl and the production address, https://api.done.com/v1.
Preview. The API is not live yet. These calls describe how it will work at launch.
You will need a customer profile that is ready for scoring. A customer profile says who you sell to. If you have none yet, see Customer profiles first, or make one in the app.
1. Make a key
Keys are made in done. under Settings, API keys. They cannot be made through the API.
When you make a key you choose:
- its reach: one workspace, a chosen set, or every workspace in your organization,
- its permission:
read,spendorfull, - a daily credit cap, and
- an expiry date.
For this quickstart, pick one workspace. Scoring is paid work, so steps 3 and 4 need spend. Step 5 makes a webhook endpoint, which changes your setup, so it needs full. To follow every step with one key, choose full. The secret is shown once. Copy it now and keep it out of source control.
To try the API without spending anything, make a test key instead. It starts with
done_test_, works only in your organization's test workspace, charges no credits, and returns realistic sample answers for paid work.
Put the key in an environment variable:
export DONE_API_KEY="done_live_..."Every call sends it in the Authorization header.
2. Check the key
GET /me tells you which workspaces the key reaches, what it may do, and how much of its daily credit cap it has used.
curl https://api.done.com/v1/me \
-H "Authorization: Bearer $DONE_API_KEY"{
"id": "key_7HsD2mQp",
"object": "me",
"name": "Zapier production",
"prefix": "done_live_ab12",
"reach": { "kind": "workspaces", "workspaces": ["ws_4fQk2LmZ", "ws_8nTb5RxC"] },
"permission": "spend",
"daily_credit_cap": 200,
"credits_used_today": 41.4,
"expires_at": "2027-01-31T00:00:00Z",
"api_version": "2026-11-01",
"test": false
}If reach.workspaces lists more than one workspace, send a Done-Workspace header on every other call. A key that reaches exactly one workspace may leave it out. See Keys, workspaces and sign-in.
3. Score one person
First, find the id of a customer profile that is ready. GET /customer_profiles lists them, newest first. Use one whose ready.for_scoring is true.
curl https://api.done.com/v1/customer_profiles \n -H "Authorization: Bearer $DONE_API_KEY"{
"object": "list",
"data": [
{
"id": "cp_6TnR4cVd",
"object": "customer_profile",
"name": "Lumen Invoicing for finance teams",
"ready": { "for_scoring": true, "for_scouts": true, "missing": [] }
}
],
"has_more": false,
"next_cursor": null
}The answer shows only the fields that matter here. If ready.for_scoring is false, ready.missing says what to add.
POST /scores scores one person against a customer profile and answers in the same call. It costs 1 credit, the same as one person in a scoring run. A person we could not read or score costs nothing.
Send the person's LinkedIn link. Send the customer_profile id too, or leave it out to use the workspace's default profile.
curl https://api.done.com/v1/scores \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: 6f1d2c0e-4b8a-4c1e-9d55-2a7c1f0b9e31" \
-H "Content-Type: application/json" \
-d '{
"linkedin_url": "https://www.linkedin.com/in/ana-lima",
"customer_profile": "cp_6TnR4cVd"
}'The Idempotency-Key is required on every call that creates, spends or sends. If your request times out, send it again with the same key and you get the first answer instead of a second charge. See Safe retries.
{
"id": "scr_5TqP2mWd",
"object": "score",
"person": {
"id": "per_9aQw1XyZ",
"object": "person",
"name": "Ana Lima",
"headline": "CFO at Lumen Pay",
"company": "Lumen Pay",
"location": "London, United Kingdom",
"linkedin_url": "https://www.linkedin.com/in/ana-lima"
},
"customer_profile": "cp_6TnR4cVd",
"scoring_run": null,
"fit": 86,
"label": "strong_fit",
"reason": "CFO at a 180-person UK fintech, the kind of buyer this profile aims for.",
"status": "done",
"excluded_because": null,
"problem": null,
"scored_at": "2026-10-23T09:14:02Z"
}fit runs from 0 to 100. label is one of strong_fit, good_fit, maybe and weak_fit. If the person or their company is on the workspace's do-not-contact list, status is excluded with excluded_because of do_not_contact. They are checked, so the call still costs 1.
4. Score a list
To score many people, start a scoring run with POST /scoring_runs. Send 2 to 500 different LinkedIn links.
First, ask what the run would do and cost. POST /scoring_runs/preview takes the same body, starts nothing and charges nothing.
curl https://api.done.com/v1/scoring_runs/preview \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_profile": "cp_6TnR4cVd",
"links": [
"https://www.linkedin.com/in/ana-lima",
"https://www.linkedin.com/in/tomas-reyes"
]
}'Then start the run:
curl https://api.done.com/v1/scoring_runs \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: 0b7d3a52-9c1f-4e0a-8a6d-5f2e91c4b7aa" \
-H "Content-Type: application/json" \
-d '{
"customer_profile": "cp_6TnR4cVd",
"links": [
"https://www.linkedin.com/in/ana-lima",
"https://www.linkedin.com/in/tomas-reyes"
],
"name": "UK finance leaders October"
}'The answer is 202 at once, with the run. The work goes on in the background. People scored for the same customer profile in the last 90 days are skipped and not charged, unless you send "skip_already_scored": false.
Poll the run every 10 to 30 seconds until status is done, failed or cancelled. A paused run resumes by itself, so keep polling.
curl https://api.done.com/v1/scoring_runs/run_3WmK9pQa \
-H "Authorization: Bearer $DONE_API_KEY"When status is done, read the scores, best fit first. You can also read them while the run is still going.
curl "https://api.done.com/v1/scoring_runs/run_3WmK9pQa/results?min_fit=70&limit=50" \
-H "Authorization: Bearer $DONE_API_KEY"The answer is a page of scores. See Lists and pages to read the rest.
5. Hear when it is finished
Polling works, but a webhook is better. Add an endpoint once, and done. calls you when a run ends. Making an endpoint changes your setup, so it needs a key with full permission.
curl https://api.done.com/v1/webhooks \
-H "Authorization: Bearer $DONE_API_KEY" \
-H "Idempotency-Key: c2a94e7b-31d8-4f6a-b0e5-7d1a3f8e2c64" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/done",
"events": ["scoring_run.completed"]
}'The answer holds the signing secret, whsec_..., once. Store it now. When the run ends, done. sends a signed scoring_run.completed event to your URL. Read the run's results with GET /scoring_runs/{id}/results.
Next: Webhooks shows how to check the signature on each delivery.