Guides
Relationships
Find warm paths between companies: who at one company is connected to people at another, who a single person can reach, and what two companies have in common.
Relationships answers the question every outbound team asks before a cold email: do we already know someone there? Give it two companies and it returns the people at the first who are connected to people at the second, ranked by how far into the other company they reach, with the shared employers and schools that connect them.
Use Relationships when you want a warm path into an account. If you want a list of people who match a description, use Search. If you want the shape of one company's workforce rather than its connections, use Org chart.
Use cases#
Three questions cover most uses of the relationship graph.
You sell from one company into another. You get the people on your side who are connected to the target, ranked, with what connects them.
One person's network matters, such as a new executive or an investor. You get the people they can reach at a target company, and how they know each other.
You are qualifying an account before anyone is ranked. You get the shared employers and schools, with how many people each side has at each one.
Each tab shows the request to send and the outcome you hold when it returns.
You want to know which senior people at Stripe can reach someone at Adyen. The first company is the side whose people come back, and people narrows that side to VPs and directors:
curl -X POST https://api.sproutsdata.ai/v1/relationships \
-H "X-API-Key: $SPROUTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"relation": "between_companies",
"companies": [
{
"value": "stripe.com",
"by": "domain",
"people": {"seniority": ["VP", "Director / Head"]}
},
{"value": "adyen.com", "by": "domain"}
],
"limit": 10
}'Outcome: people at Stripe, ranked by how many people at Adyen each one can reach. Every row says why in via (the shared employers and schools, with dates and roles) and in match_type, a plain-language reason such as "Previously worked at Palantir Technologies". The response also lists the shared institutions with a people count on each side.
How it works#
The relationship routes read the affiliation graph: who worked or studied where, and when. That is a different corpus from the entity index that Search reads, which is why these are separate routes even though their rows are people.
- Scope: every route requires
dsp.search.read. - Billing:
POST /v1/relationshipsand/reachare billed underdsp.relationships: 2 credits for the first 10 results, then 1 credit per next 10. A call that returns nobody costs nothing./institutionsis 2 credits flat, whatever it returns. See Credits & usage. - Retries: all four routes honour an
Idempotency-Keyheader, so a retried request does not pay twice for the same rows.
Order is the contract
For between_companies, the first company's people are what comes back, and the second company is who they are connected to. Swap the two and you ask the mirror question. There is no reverse flag, because the order already says it.
people belongs to a company rather than to the request, so each side is filtered on its own:
| Request | Question it asks |
|---|---|
people on the first company | Which of their VPs can reach anyone at the second company |
people on the second company | Who at the first company can reach the second company's VPs |
people accepts seniority, department and country, up to 20 values each. Seniority is one of C-Suite, VP, Director / Head, Manager, IC, Entry and In Training. Department uses the same vocabulary as the org chart.
Identify companies by domain
Each company is {value, by}, where by is domain, li_url, name or auto (the default, which infers it from the value's shape). Prefer domain or li_url. A name is not unique, and a name that matches several companies with no clear winner is refused with 422 relationship.anchor_ambiguous:
{
"status": 422,
"code": "relationship.anchor_ambiguous",
"detail": "3 companies match 'Acme' with no clear winner",
"extra": { "anchor": "acme", "candidates": ["acme.com", "acme-industries.com", "acme-labs.io"] }
}extra.candidates lists what the name could have meant, so you can send one of them back as a domain.
What connection_basis changes
connection_basis | Two people count as connected when they were at the shared institution |
|---|---|
overlapping (default) | At the same time |
shared | At some point, not necessarily together |
The difference is large. On a big former employer, one measured row reaches 16,630 people under overlapping and 100,085 under shared. The basis is echoed on the response, because the counts cannot be read without it.
Reading a row
Two numbers on each row are the ones to act on:
number_of_contacts_overlapping_tenure_withis how many distinct people at the other company this person can reach.0is a checked answer: we counted and found nobody.nullmeans the count was not attempted.match_reason_countis how many distinct institutions connect them.
Every via entry carries a match_confidence:
match_confidence | How the institution was matched |
|---|---|
url | Identified by the institution's canonical LinkedIn URL |
edu | Identified from a school record |
name | Identified by a normalised name. Names are not unique, so this is an inference rather than a verified link |
The row's top-level match_type lists the same reasons as via, strongest first.
Ask in words
When you would rather not decide which route a question needs, send it as a sentence to POST /v1/relationships/ask:
curl -X POST https://api.sproutsdata.ai/v1/relationships/ask \
-H "X-API-Key: $SPROUTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "who at Adyen do we know from Stripe", "limit": 10}'Read two fields before the rows:
routenames the question it turned out to be:relationships,reach,institutions,compare(two ways in, weighed against each other) orfan_out(people, each with who they can reach). Exactly one field of that name holds the answer, in that route's own shape.readingsays what was understood.spanis the part of your question the answer covers, andwarningslists anything that was widened, capped or could not be applied. An empty list means nothing was dropped.
/ask is billed under its own action, dsp.relationships.ask, at the same price as the route it picks, and reports its cost in a top-level credits_charged. A sentence the graph cannot answer is refused with 422 request.unsupported. extra.kind names the reason, and extra.try_instead, when present, suggests another way to ask.
Pagination
POST /v1/relationships and /reach page with next_cursor, exactly like Search. On /ask, only a relationships answer has further pages.
/institutions is not paginated. One aggregation counts everything, so has_more is always false. Read truncated instead: it is true when more institutions qualified than limit returned (default 200, up to 1,000).
Errors
Everything in the errors guide applies. The ones specific to relationships:
| Status | Code | Meaning |
|---|---|---|
| 422 | relationship.anchor_ambiguous | A company named by name matched several records. Send one of extra.candidates as a domain |
| 422 | request.unsupported | A question in words that this graph cannot answer. See extra.kind and extra.try_instead |
| 422 | request.invalid | The request broke a rule: for example, between_companies without exactly two companies, or query sent beside the structured fields |
| 404 | request.unsupported | Relationships are not enabled in this deployment |
Best practices#
- Identify companies by domain. It removes the one error that only names can cause,
relationship.anchor_ambiguous. - Put the company whose people you want first. The order decides what comes back; there is no flag to flip it.
- Start with
/institutionswhen qualifying an account. At 2 credits flat it tells you whether a warm path is likely before you pay to rank people. - Treat
connection_basis: "shared"as a wide net. It counts everyone who ever passed through an institution, so use it to find any path at all andoverlappingto find a credible one. - Check
readingon every/askanswer. If the sentence was read as a different question, the rows will look valid but answer something else.
For every field and parameter, see the API reference for Relationships and Ask a relationship question.
