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.

A warm path between two companies

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.

Who one person can reach

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.

What two companies have in common

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/relationships and /reach are billed under dsp.relationships: 2 credits for the first 10 results, then 1 credit per next 10. A call that returns nobody costs nothing. /institutions is 2 credits flat, whatever it returns. See Credits & usage.
  • Retries: all four routes honour an Idempotency-Key header, 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:

RequestQuestion it asks
people on the first companyWhich of their VPs can reach anyone at the second company
people on the second companyWho 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_basisTwo people count as connected when they were at the shared institution
overlapping (default)At the same time
sharedAt 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_with is how many distinct people at the other company this person can reach. 0 is a checked answer: we counted and found nobody. null means the count was not attempted.
  • match_reason_count is how many distinct institutions connect them.

Every via entry carries a match_confidence:

match_confidenceHow the institution was matched
urlIdentified by the institution's canonical LinkedIn URL
eduIdentified from a school record
nameIdentified 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:

  • route names the question it turned out to be: relationships, reach, institutions, compare (two ways in, weighed against each other) or fan_out (people, each with who they can reach). Exactly one field of that name holds the answer, in that route's own shape.
  • reading says what was understood. span is the part of your question the answer covers, and warnings lists 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:

StatusCodeMeaning
422relationship.anchor_ambiguousA company named by name matched several records. Send one of extra.candidates as a domain
422request.unsupportedA question in words that this graph cannot answer. See extra.kind and extra.try_instead
422request.invalidThe request broke a rule: for example, between_companies without exactly two companies, or query sent beside the structured fields
404request.unsupportedRelationships 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 /institutions when 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 and overlapping to find a credible one.
  • Check reading on every /ask answer. 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.