API reference
Find people at companies
People who work at up to 25 companies, filtered on title, seniority, department and country. One call reads one page across all the companies and returns at most 25 people, so a big company can fill it: set per_company to search each company on its own and get its top people in one call. Each person costs 1 credit. A company that cannot be matched, and a page with nobody on it, cost nothing.
Name a company by id (cmp_… from an earlier row), domain, or linkedin_url. A domain without a known LinkedIn page is looked up by its name; when that finds nothing, GET /companies/lookup finds the page for free. Send next_cursor back as cursor with the same companies and filters. No profile is fetched: use POST /person/enrich with person_ids for the full profile and a work email.
This is not a buying signal. signal_type on each row is null. The person did not do anything; they hold a role at a company you named.
Authentication
Send Authorization: Bearer gtk_…. Create the key under Connect assistant → API keys. A missing, invalid or revoked key is 401. A valid key while this API is not enabled for your organization answers 403 api_not_enabled, with what the key can do instead. Every response includes mySDR-Api-Version, mySDR-Request-Id and Cache-Control: no-store, and a response to an accepted key also X-RateLimit-* (so not a 401, a 405, an OPTIONS or a 404 for an unknown path).
Body parameters
companiesobject[]· required — 1 to 25 companies. Each object has exactly one ofid,domainorlinkedin_url.filtersobject· required — At least one oftitles(job titles, up to 10),seniority(c_level,vp,director,manager) ordepartments(ceo,sales,marketing,finance,operations,hr,it,talent_acquisition,engineering,product,customer_success,data,procurement,legal).countriesis ISO alpha-2, up to 20. Titles rank people but do not exclude them. Departments, seniority and countries do: a department filters on LinkedIn's own function of the role (engineeringkeeps engineering and IT), exceptceoandchief_of_staff, which only rank on title (ceoalone looks at C-level and owners). Values in one list are alternatives.rolesis the earlier name oftitlesand still works.per_companyinteger | null— At most this many people per company, 1 to 25: each company is searched on its own and the call returns their top people, in the order ofcompanies, without a next page. Not together withcursor.limitinteger— At most this many people, 1 to 100. Withoutper_companyone call still returns at most 25. Defaults to 25.cursorstring | null—next_cursorof the previous response, with the same companies and filters.max_creditsinteger | null— Stop before the next person would pass this.
Response
objectstring· required — Alwayslist.dataobject[]· required — People.idisper_…(send it to POST /person/enrich asperson_ids).from_company_idis the company they were found at.signalsis the current role.companiesobject[]· required — One entry per company you sent, in order:statusmatched,not_foundorinvalid,company_id,rows,message.company_idis set once people of the company were delivered (now or in the last 30 days): send it asidlater. A matched company without anyone has none; send its domain or page again.next_cursorstring | null· required — The next page. Always null withper_company.credits_usedinteger· required — People delivered times 1.truncated_bystring | null· required —max_creditswhen the cap left people out.
Credits
1 credit per person delivered. Misses are free. Errors and empty lookups are free. A call that spent credits puts that number in credits_used, in X-Credits-Used and in X-Credits-Charged. When the wallet can be read, the response also sends X-Credits-Remaining.
Errors
- 503
service_unavailable— A company could not be looked up just now.paramnamescompanies[i]. Nothing was charged. - 400
invalid_request— The body is not valid JSON, a field is unknown or has the wrong type, or a value is not allowed. - 401
authentication_error— The Authorization header is missing, or the key is unknown or revoked. - 403
permission_error— API access is not part of your plan, or your account is suspended. - 403
api_not_enabled— The key is valid, but the Signals API or the Company API is not enabled for your organization yet. The error says what this key can do. - 429
rate_limit_error— More than 60 requests per minute, or more than 3 at the same time, on one key. Wait for the Retry-After header. - 429
daily_limit_reached— The request could take your organization over its daily credit limit. The limit resets at midnight (Europe/Brussels). - 402
insufficient_credits— The credit balance is lower than this request could cost. Nothing was charged. Add credits, or send a smaller request. The error includes code, fix and a link to the credits docs. - 502
upstream_error— The data source did not answer. Retry later. - 503
service_unavailable— The API is temporarily unavailable. Retry later. - 500
internal_error— Something went wrong on our side. - 402
max_credits_exceeded— max_credits is lower than the credits of the first row, so nothing could be returned. Nothing was charged; raise max_credits or ask for fewer rows.
Example
cURL
curl -X POST "https://mysdr.app/api/v1/leads" \
-H "Authorization: Bearer $MYSDR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"companies": [
{
"linkedin_url": "https://www.linkedin.com/company/acme-analytics"
}
],
"filters": {
"titles": [
"CFO",
"Head of Finance"
],
"seniority": [
"c_level",
"vp"
],
"countries": [
"BE"
]
},
"limit": 3,
"max_credits": 15
}'
JavaScript
const response = await fetch('https://mysdr.app/api/v1/leads', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MYSDR_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
"companies": [
{
"linkedin_url": "https://www.linkedin.com/company/acme-analytics"
}
],
"filters": {
"titles": [
"CFO",
"Head of Finance"
],
"seniority": [
"c_level",
"vp"
],
"countries": [
"BE"
]
},
"limit": 3,
"max_credits": 15
})
});
const body = await response.json();
Python
import json
import os
import urllib.request
payload = {
"companies": [
{
"linkedin_url": "https://www.linkedin.com/company/acme-analytics"
}
],
"filters": {
"titles": [
"CFO",
"Head of Finance"
],
"seniority": [
"c_level",
"vp"
],
"countries": [
"BE"
]
},
"limit": 3,
"max_credits": 15
}
request = urllib.request.Request(
"https://mysdr.app/api/v1/leads",
headers={
"Authorization": f"Bearer {os.environ['MYSDR_API_KEY']}",
"Content-Type": "application/json"
},
data=json.dumps(payload).encode(),
method="POST",
)
with urllib.request.urlopen(request) as response:
body = json.load(response)
Example response
{
"object": "list",
"data": [
{
"id": "per_01J9Z6P8C8V0K3W6T2N8R5M1XK",
"object": "person",
"signal_type": null,
"from_company_id": "cmp_01J9Z6P8C8V0K3W6T2N8R5M1XB",
"credits_charged": 1,
"person": {
"full_name": "Jane Example",
"title": "Chief Financial Officer",
"linkedin_url": "https://www.linkedin.com/in/jane-example"
}
}
],
"companies": [
{
"input": {
"linkedin_url": "https://www.linkedin.com/company/acme-analytics"
},
"status": "matched",
"company_id": "cmp_01J9Z6P8C8V0K3W6T2N8R5M1XB",
"rows": 1,
"message": null
}
],
"next_cursor": null,
"credits_used": 1,
"truncated_by": null,
"sources": [
"linkedin"
],
"notes": []
}