Organization relationships
An organization can point to other organizations it is related to: the network it is a chapter of, the foundation that fiscally sponsors it, the organizations that carried on its work, or the record that should be used instead of it. These go in relationships, in a list for each category and direction. Other names the organization goes by go in aliases, not in a relationship.
| List | Each entry says | Standard kind values |
|---|---|---|
parents |
org is above this organization |
chapter, department, branch, subsidiary, fiscalSponsor, dba |
children |
org is below this organization |
Same as parents |
succeededBy |
org carries on all or part of this organization |
merger, acquisition, divestiture, split |
succeeds |
This organization carries on all or part of org |
Same as succeededBy |
recordReplacedBy |
org’s record should be used instead of this record |
duplicate, merged |
recordReplaces |
This record should be used instead of org’s record |
Same as recordReplacedBy |
otherRelationships |
This organization is connected to org, possibly with no direction |
None |
Every entry has the same shape:
orgis required and is anOrgRef: the other organization’sid,name, and optionalidentifiers. A writer identifies the target byid, and the target must already exist in the receiver. Identifiers sent with a target are informational; the receiver fills in the target’snameandidentifiersfrom its own record. See Updating relationships.kindis optional. It is an extensible enum: a standardvaluefor the list, or"value": "custom"with the subtype incustomValue.startDateandendDateare optionalYYYY-MM-DDdates.statusis optional and isactiveorinactive. It describes the relationship, not either organization. It has no default and isn’t derived from the dates.
An entry with only org is valid in every list. List order carries no meaning, such as a primary parent. A relationship gives no authority over the other organization.
Parents and children
Section titled “Parents and children”The list name gives the category and direction; kind narrows it to a subtype. parents and children cover more than containment: a fiscal sponsor is a parent of kind fiscalSponsor, so a project can list a chapter parent and a different sponsor together. Don’t treat every parent as an owner or container.
{ "id": "01912a8b-7c3d-7890-abcd-ef1234567890", "name": "Riverside Reading Project", "relationships": { "parents": [ { "org": { "id": "01912a8b-7c3d-7891-abcd-ef1234567891", "name": "National Reading Network" }, "kind": { "value": "chapter" } }, { "org": { "id": "01912a8b-7c3d-7892-abcd-ef1234567892", "name": "Riverside Community Foundation", "identifiers": { "org:us:ein": { "registry": { "code": "org:us:ein" }, "id": "472345678" } } }, "kind": { "value": "fiscalSponsor" }, "startDate": "2024-07-01", "status": "active" } ] }}A provider can state a relationship from whichever record it maintains. Here the network lists a chapter without the chapter’s record listing the network:
{ "id": "01912a8b-7c3d-7891-abcd-ef1234567891", "name": "National Reading Network", "relationships": { "children": [ { "org": { "id": "01912a8b-7c3d-7890-abcd-ef1234567890", "name": "Riverside Reading Project" }, "kind": { "value": "chapter" } } ] }}The protocol doesn’t require the reverse entry, complete lists, or agreement between the two records.
Subtypes the standard values don’t name
Section titled “Subtypes the standard values don’t name”department names an internal unit; it isn’t defined to cover every internal level. A provider can name another level with a custom kind, or leave kind out when it doesn’t know the subtype:
{ "id": "01912a8b-7c3d-7896-abcd-ef1234567896", "name": "Example Division of Rural Programs", "relationships": { "parents": [ { "org": { "id": "01912a8b-7c3d-7897-abcd-ef1234567897", "name": "Example Center for Community Health" }, "kind": { "value": "custom", "customValue": "division" } }, { "org": { "id": "01912a8b-7c3d-7898-abcd-ef1234567898", "name": "Example Regional Health Partnership" } } ] }}There is no generic parent kind: an entry without kind already says the other organization is a parent.
Trading-name records
Section titled “Trading-name records”Some systems, such as grants management systems that track each name a grantee trades under, keep a separate record for each trading name. That record points up at the legal entity it belongs to with a dba entry in parents, meaning this record is a name the referenced legal entity does business under. Its name is the trading name. Here the alliance’s gallery has a record of its own:
{ "id": "01912a8b-7c3d-7890-abcd-ef12345678a1", "name": "The Gallery on Main", "relationships": { "parents": [ { "org": { "id": "24354657-c5d6-4be8-99a0-1b2c3d4e5f60", "name": "Example Riverside Arts Alliance, Inc." }, "kind": { "value": "dba" } } ] }}In children, a dba entry means the referenced record is a trading-name record of this organization. Most systems don’t keep a record per trading name; they list the names in the legal entity’s aliases instead. Use a dba record only when the trading name has a record of its own, and don’t also list that name in aliases; see Aliases.
Succession
Section titled “Succession”Succession is about organizations. A list can hold several entries of the same subtype, such as the two organizations formed by a split:
{ "id": "01912a8b-7c3d-7890-abcd-ef1234567890", "name": "Riverside Reading Project", "relationships": { "succeededBy": [ { "org": { "id": "01912a8b-7c3d-7893-abcd-ef1234567893", "name": "Riverside Reading East" }, "kind": { "value": "split" }, "startDate": "2026-01-01" }, { "org": { "id": "01912a8b-7c3d-7894-abcd-ef1234567894", "name": "Riverside Reading West" }, "kind": { "value": "split" }, "startDate": "2026-01-01" } ] }}{ "id": "01912a8b-7c3d-7899-abcd-ef1234567899", "name": "Example Reading Partners", "relationships": { "succeeds": [ { "org": { "id": "01912a8b-7c3d-789a-abcd-ef123456789a", "name": "Example Literacy Coalition" }, "kind": { "value": "merger" }, "startDate": "2025-01-01" }, { "org": { "id": "01912a8b-7c3d-789b-abcd-ef123456789b", "name": "Example Book Bank" }, "kind": { "value": "merger" }, "startDate": "2025-01-01" } ] }}A rename is not succession: a renamed organization keeps its record and changes its name.
Record replacement
Section titled “Record replacement”Record replacement is about records in a provider’s system, not organizations. A merged entry means a provider combined records, which is different from a merger of organizations. A provider’s workflow may treat duplicate and merged alike; they needn’t be exclusive. The protocol doesn’t prescribe how a provider merges, deletes, or redirects records.
{ "id": "01912a8b-7c3d-789c-abcd-ef123456789c", "name": "Example Health Clinic", "relationships": { "recordReplacedBy": [ { "org": { "id": "01912a8b-7c3d-789d-abcd-ef123456789d", "name": "Example Health Clinic" }, "kind": { "value": "duplicate" } } ] }}{ "id": "01912a8b-7c3d-789d-abcd-ef123456789d", "name": "Example Health Clinic", "relationships": { "recordReplaces": [ { "org": { "id": "01912a8b-7c3d-789c-abcd-ef123456789c", "name": "Example Health Clinic" }, "kind": { "value": "duplicate" } }, { "org": { "id": "01912a8b-7c3d-789e-abcd-ef123456789e", "name": "Example Health Clinic, Inc." }, "kind": { "value": "merged" } } ] }}Other relationships
Section titled “Other relationships”otherRelationships holds connections outside the named categories, which need not have a direction. An entry with only org is valid. It defines no standard subtypes, so a stated kind is always custom:
{ "id": "01912a8b-7c3d-7890-abcd-ef1234567890", "name": "Riverside Reading Project", "relationships": { "otherRelationships": [ { "org": { "id": "01912a8b-7c3d-7895-abcd-ef1234567895", "name": "Riverside Literacy Coalition" } }, { "org": { "id": "01912a8b-7c3d-789f-abcd-ef123456789f", "name": "Example County Library" }, "kind": { "value": "custom", "customValue": "programPartner" } } ] }}Aliases
Section titled “Aliases”aliases lists other names the same organization goes by, such as a trading name or a short form of its legal name, as plain strings on the organization itself. They are not separate organizations, and they are not a history of former names. Each alias is a non-empty string, and the list has no repeats.
Don’t list a name in aliases that has its own live trading-name record linked to this organization by a dba entry in either record, parents on the trading-name record or children on this one, so a reader doesn’t count the same name twice. A name can go in aliases when no live dba record for it remains, for example when that record was replaced, as a duplicate or merged record, by the legal entity’s own record. The schema doesn’t check this.
{ "id": "24354657-c5d6-4be8-99a0-1b2c3d4e5f60", "name": "Example Riverside Arts Alliance, Inc.", "aliases": ["Riverside Arts", "RAA"]}Updating relationships
Section titled “Updating relationships”Relationships are updated with the same JSON Merge Patch as the rest of the organization profile. Each list is an array, so a patch replaces the lists it addresses whole and leaves the other lists unchanged. There is no append, merge by ID, single-entry change, or automatic reverse entry: to change one entry, send the full list with whole entries.
In a patch, org names the other organization by id. The receiver rejects an id it doesn’t recognize. It ignores any name or identifiers sent with the id and fills both in from its own record, so reads and revision snapshots return a full OrgRef. A revision’s patch is recorded as received, so a target name or identifiers there isn’t authoritative; the read and the revision’s snapshot carry the filled-in values. A writer can send id alone, or resend entries copied from a read without removing their names. Schema validation only checks shape; it doesn’t look up or fill in the target.
{ "relationships": { "parents": [ { "org": { "id": "01912a8b-7c3d-7891-abcd-ef1234567891" }, "kind": { "value": "chapter" } }, { "org": { "id": "01912a8b-7c3d-7892-abcd-ef1234567892" }, "kind": { "value": "fiscalSponsor" }, "startDate": "2024-07-01", "endDate": "2026-06-30", "status": "inactive" } ] }}{ "relationships": { "recordReplacedBy": null, "children": [] }}{ "relationships": null, "aliases": ["Riverside Arts"]}| In a patch | Effect |
|---|---|
| A list | Replaces that whole list. Other lists are unchanged. |
[] |
Leaves a present, empty list. Other lists are unchanged. |
null for a list |
Removes that list. Other lists are unchanged. |
null for relationships |
Removes every relationship list. |
Entries in a list are replaced whole, so leave out an entry’s optional kind, dates, or status rather than sending null.
Two writers changing the same list at the same time can overwrite each other.
Reading parents
Section titled “Reading parents”Because each list holds every supplied entry of its category and direction, a consumer reads one list whatever subtypes the entries use, and filters when it wants one subtype:
type OrgRef = { id: string; name: string };type Kind = { value: string; customValue?: string; description?: string };type Relationship = { org: OrgRef; kind?: Kind; startDate?: string; endDate?: string; status?: "active" | "inactive";};
/** The organizations an entry list points to, whatever their subtypes. */function relatedIds(entries?: Relationship[]) { return (entries ?? []).map((entry) => entry.org.id);}
/** The entries of one standard or custom subtype. */function ofKind(entries: Relationship[] | undefined, kind: string) { return (entries ?? []).filter( (entry) => entry.kind?.value === kind || (entry.kind?.value === "custom" && entry.kind.customValue === kind), );}Following parents from record to record visits the parents each record supplies. With several parents allowed, a walk can branch and reach the same organization more than once. Because sponsors are parents too, a walk can leave a containment chain, and it only reaches entries the records state.
What the schema does not check
Section titled “What the schema does not check”The published schema checks shape: which lists exist, that every entry has an org, that every org in a read has an id and name and every org in a patch has an id, which kind values each list accepts, the date format, and the status values. It doesn’t fill in an ID-only org, which the receiver does, and it doesn’t check facts about other records: whether the other organization exists, whether a reverse entry exists or agrees, or whether dates and status agree with each other. The protocol leaves those to the systems that hold the records and doesn’t ask them to store or maintain a relationship graph.