API reference
Get Company Tech Stack
Send domains (company websites) and/or linkedin_urls (LinkedIn company pages), up to 25 together. Each gets its own entry in results, in the order you sent them (domains first). A technology appears when the company’s job posts mention it: first_seen_on and last_seen_on are the first and the last job post that did, jobs_mentioning how many, and confidence how sure the match is. A company that rarely hires has no tech stack here.
By default you get the technologies seen in the last 12 months with medium or high confidence, the most certain and most mentioned first, at most 50 per company; seen_within_months, min_confidence and limit change that, and left_out says what the defaults hid. To answer "does this company use X?", send technologies: asked then says yes or no per technology, with the evidence. A name the catalog does not know is 400 unknown_technology with the closest names in suggestions, before anything is charged. For one kind of tool, send categories (e.g. CRM, Marketing Automation, ERP).
Some names are also common words or job titles in job posts ("streamline", "team leader"). A word that is almost never the product is left out unless you ask for it by name (left_out.common_words counts them); a real product with such a name is shown with ambiguous: true, after the rest. Check its evidence before you rely on it.
A company costs the same whether your filters keep fifty technologies or none: the lookup was made. Every call is charged, also a repeat of the same company, so to answer several questions about one company, ask once without filters and answer from that. Not found, invalid, capped or failed entries cost nothing, and the same company in one call (also its domain and its LinkedIn page) is looked up and charged once. A domain finds a company more often than a LinkedIn page.
Authentication
Send Authorization: Bearer gtk_…. Create the key under Connect assistant → API keys. This endpoint answers for every key with API access: it is not behind the Signals API or the Company API. A missing, invalid or revoked key is 401. Every response includes mySDR-Api-Version, mySDR-Request-Id and Cache-Control: no-store, and a response to an accepted key also X-RateLimit-*; every error has type, message, param and request_id.
Body parameters
domainsstring[]— Company websites or domains, e.g.acme.com(a URL or an email address works too).linkedin_urlsstring[]— LinkedIn company pages, e.g.https://www.linkedin.com/company/acme-analytics.technologiesstring[]— Only these technologies, by slug or name, up to 20: "does this company use HubSpot?".askedanswers per technology. A name the catalog does not know is a400, free. Leave it out for the whole stack.categoriesstring[]— Only technologies of these kinds, up to 20, e.g.CRM,ERP,Marketing Automationor a whole area such asSalesorHR. Every word must be in the category or the technology’s name (CRMalso finds HubSpot CRM and HubSpot). Withtechnologiestoo, a technology must match both.min_confidencestring— The weakest evidence to include. Defaults tomedium. One of:low,medium,high.seen_within_monthsinteger— Only technologies a job post mentioned in the last this many months, 1 to 120. Defaults to 12.limitinteger— Technologies per company, 1 to 200. Defaults to 50.max_creditsinteger— Stop before the call costs more than this. A company is looked up only while it still fits; one we do not know costs nothing and leaves the room to the next. Entries left over arecapped. Below the price of one company the call is402max_credits_exceeded.
Response
resultsobject[]— One entry per company you sent, in the same order.results[].inputstring— The domain or URL as you sent it.results[].match_typestring—domainorlinkedin_url. One of:domain,linkedin_url.results[].statusstring—matched,not_found(no job posts of this company in our data, or a LinkedIn page we could not match),invalid(not a company domain or LinkedIn company page;messagesays what to send instead),capped(not looked up:max_creditshad no room left) orerror(retry later). One of:matched,not_found,invalid,capped,error.results[].companyobject—name,domainandlinkedin_url, as far as we know them.results[].technologiesobject[]—slug,name,category,parent_category,confidence(low,mediumorhigh: how sure the match is),first_seen_onandlast_seen_on(the first and the last job post that mentioned it) andjobs_mentioning(in how many job posts), plusjobs_last_30_days,rank_in_category(1 = the most mentioned tool of its kind at this company) andambiguous(true when the name is also a common word or job title in job posts).results[].technologies_totalinteger— Every technology we know for this company, before your filters (the data returns its 500 most certain).results[].technologies_total_cappedboolean— Only when true: the data returned its 500 most certain technologies and knows more, with less evidence.results[].askedobject[]— Only withtechnologies: one entry per technology you asked for,technologyas you sent it andfoundtrue or false; when found,slug,name,confidence,last_seen_on,jobs_mentioning,meets_filters: falsewhen it is there but older or weaker than your filters, andambiguouswhen its name is also a common word.results[].technologies_matchinginteger— How many passed your filters, beforelimit.results[].left_outobject— Only when something was hidden:lower_confidenceandolder(hidden bymin_confidenceandseen_within_months) andcommon_words(common words the data reads as a product, hidden unless you ask for them by name), how many.results[].observed_atstring— When this tech stack was fetched (ISO 8601); kept up to 30 days.results[].credits_chargedinteger— 3 on the first entry of a company we know, otherwise 0.results[].messagestring— Why an entry has no technologies, and what to send instead.credits_usedinteger— Credits this call used.truncated_bystring— Only whenmax_creditsleft entriescapped:max_credits. One of:max_credits.sourcesstring[]— Always["job_postings"].
Credits
3 credits per company we know; a company we do not know costs nothing. 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
- 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. - 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/company/tech-stack" \
-H "Authorization: Bearer $MYSDR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domains": [
"acme-analytics.example"
],
"categories": [
"CRM",
"Marketing Automation"
]
}'
JavaScript
const response = await fetch('https://mysdr.app/api/v1/company/tech-stack', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MYSDR_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
"domains": [
"acme-analytics.example"
],
"categories": [
"CRM",
"Marketing Automation"
]
})
});
const body = await response.json();
Python
import json
import os
import urllib.request
payload = {
"domains": [
"acme-analytics.example"
],
"categories": [
"CRM",
"Marketing Automation"
]
}
request = urllib.request.Request(
"https://mysdr.app/api/v1/company/tech-stack",
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
{
"results": [
{
"input": "acme-analytics.example",
"match_type": "domain",
"status": "matched",
"company": {
"name": "Acme Analytics",
"domain": "acme-analytics.example",
"linkedin_url": null
},
"technologies": [
{
"slug": "hubspot",
"name": "HubSpot",
"category": "Marketing Automation Platforms",
"parent_category": "Marketing",
"confidence": "high",
"first_seen_on": "2024-03-12",
"last_seen_on": "2026-10-02",
"jobs_mentioning": 14,
"jobs_last_30_days": 2,
"rank_in_category": 1,
"ambiguous": false
}
],
"technologies_total": 61,
"technologies_matching": 1,
"observed_at": "2026-10-25T09:12:04.000Z",
"credits_charged": 3
}
],
"credits_used": 3,
"sources": [
"job_postings"
]
}