Supply-chain graph
Typed single-hop edges that let you reconstruct who a company ships to, who owns it, and who litigates against it — without stitching together six separate connectors.
Three sub-graphs cooperate:
| Sub-graph | Filing primitive | What it returns |
|---|---|---|
Entity.parent | Schedule 13D/G | Controlling shareholder (>50%) with reported ownership percentage |
Entity.subsidiaries | Exhibit 21 (10-K / 20-F) | Consolidated legal subsidiaries with jurisdictions |
Entity.concentration | XBRL segment filings | HHI + top shares per product / segment / geography / customer |
Entity.relationships | All of the above + 13F + alt-data | Flat list of typed edges (CUSTOMER, SUBSIDIARY, GOVERNMENT_CUSTOMER, PARTNER, ADVERSARIAL, OWNERSHIP) |
relationships is the unified view — if you only want one call per entity, use that. subsidiaries and concentration give you the structured primitives backing it.
Parent company
Entity.parent returns the controlling shareholder when one exists — the filer of the most recent Schedule 13D/G where percentOwned exceeds 50%. Null when no shareholder crosses the majority threshold.
{
entitiesByTickers(tickers: ["LCID", "IMVT", "AAPL", "GOOGL"]) {
tickers
parent {
name
cik
percentOwned
source { connector url asOf ref }
}
}
}
Expected: LCID → Ayar Third Investment Co (~64%, Saudi PIF vehicle); IMVT → Roivant Sciences Ltd. (~55%); AAPL and GOOGL → null (no single 13D/G filer crosses 50%).
Percent is parsed from Item 13 (SC 13D) / Item 9 (SC 13G): "Percent of class represented by amount in row (11)". "Less than 1%" is normalized to 0.5.
What the field captures
Post-IPO secondary 13D filings (spin-offs, leveraged buyouts, private takeovers, sovereign-wealth stakes). Ownership is reported per-filer — when a filer's most recent filing reports < 50%, they're excluded even if an older filing was above the threshold (a divestiture wiping out prior control).
What it won't catch
Majority ownership disclosed via S-1 / 10-K registration (e.g. Intel's ~88% of MBLY, SoftBank's ~90% of ARM) — those parents don't file Schedule 13D because ownership is already on the registration statement. For that case, pair this field with Entity.subsidiaries on the parent company, or use Entity.relationships(filter: { types: [OWNERSHIP] }).
Super-voting founder control (Zuckerberg at META, Page/Brin at GOOGL) is reported as the economic percentage, not the voting percentage — so those filings correctly fall below the 50% gate.
Consolidated subsidiaries
Entity.subsidiaries returns the subsidiary table parsed from the most recent 10-K or 20-F Exhibit 21.
{
entityByTicker(ticker: "AAPL") {
subsidiaries {
accessionNumber
form
filingDate
exhibitUrl
count
subsidiaries { name jurisdiction }
}
}
}
Returns null when the entity has no recent 10-K / 20-F on file (foreign private issuers, non-public entities).
Revenue concentration (HHI)
Entity.concentration computes Herfindahl-Hirschman Index scores from XBRL segment disclosures. Each dimension (product / segment / geography / customer) returns hhi, count, total, and components ordered largest-first.
{
entityByTicker(ticker: "AAPL") {
concentration {
form periodEnd
product { hhi count total components { label value share } }
geography { hhi count total components { label value share } }
segment { hhi count total components { label value share } }
customer { hhi count total components { label value share } }
}
}
}
customer is null unless the issuer disclosed major-customer concentration under ASC 280 (MajorCustomersAxis). Dimensions the issuer doesn't disclose are also null — they are never fabricated from adjacent data.
Relationship edges
Entity.relationships(filter: RelationshipFilterInput) is the single call that rolls everything up. Each edge carries:
type— one ofCUSTOMER,SUBSIDIARY,GOVERNMENT_CUSTOMER,PARTNER,ADVERSARIAL,OWNERSHIPdirection—OUT(the subject → counterparty) orIN(counterparty → subject)disclosure—SELF_REPORTED(company's own filing) vsTHIRD_PARTY(court docket, trial registry, etc.)confidence— 0.0 – 1.0 (anonymized customer labels like "Customer A" emit at0.4)counterpartyName,counterpartyTicker,counterpartyCik— what you hop to nextsharePct,valueUsd,context— edge metadata when availablesource—{ connector, url, asOf, ref }provenance
{
entityByTicker(ticker: "AAPL") {
relationships(filter: {
types: [SUBSIDIARY, CUSTOMER, OWNERSHIP, PARTNER, GOVERNMENT_CUSTOMER]
minConfidence: 0.5
limit: 20
sort: DESC
}) {
type direction confidence
counterpartyName counterpartyTicker counterpartyCik
sharePct valueUsd context
source { connector asOf ref url }
}
}
}
Filter reference
input RelationshipFilterInput {
types: [RelationshipType!] # CUSTOMER | SUBSIDIARY | GOVERNMENT_CUSTOMER | PARTNER | ADVERSARIAL | OWNERSHIP
directions: [RelationshipDirection!] # OUT | IN
minConfidence: Float # 0.0 – 1.0
minValue: Float # USD floor on valueUsd
since: String # ISO 8601 on source.asOf
until: String # ISO 8601 on source.asOf
limit: Int # default 50, cap 500
offset: Int
sort: SortDirection # DESC default (newest asOf first)
}
Two-hop traversal (supply-chain walks)
A client can reconstruct "Apple → chips supplier → supplier's geography" with two batched calls. Hop 0 pulls Apple's outgoing edges; hop 1 batches the counterparty tickers back through entitiesByTickers to pull their concentration.geography and incoming CUSTOMER edges.
- Hop 0 — subject edges
- Hop 1 — fan out to counterparties
{
entityByTicker(ticker: "AAPL") {
relationships(filter: {
types: [CUSTOMER, SUBSIDIARY, OWNERSHIP, PARTNER]
directions: [OUT]
minConfidence: 0.5
limit: 50
}) {
type counterpartyTicker counterpartyName sharePct context
source { connector asOf }
}
}
}
{
entitiesByTickers(tickers: ["INTC", "AVGO", "QCOM"]) {
name tickers
concentration {
geography { components { label share value } }
customer { components { label share value } }
}
relationships(filter: {
directions: [IN]
types: [CUSTOMER, GOVERNMENT_CUSTOMER]
minConfidence: 0.5
limit: 10
}) {
type direction counterpartyName sharePct
}
}
}
Combining with alt-data
Because relationships is aggregated from the existing connectors, pulling it alongside litigation or governmentContracts is deduplicated at the request-scoped cache level — you pay for one upstream hit, not two.
{
entitiesByTickers(tickers: ["LMT", "RTX"]) {
relationships(filter: { types: [GOVERNMENT_CUSTOMER], minValue: 1000000, limit: 5 }) {
counterpartyName valueUsd context source { asOf ref }
}
governmentContracts(filter: { minAmount: 1000000, limit: 5 }) {
awardId amount agency awardType actionDate
}
}
}
See Sub-graphs for batching semantics and Filtering & sorting for generic ArrayFilterInput usage.