# Get global Contributor Network lineage

```http
GET /api/public/v1/contributor-network/graph
```

**Scope**: `contributor-network.read`.

Returns the public Contributor Network lineage forest across supported competitions: item nodes and immutable parent-child edges, without kind-specific payloads. Reading the graph requires neither competition enrollment nor account setup.

## Query parameters

| Parameter | Type, requirement, default, and meaning |
| :--- | :--- |
| `competitionId` | **Optional string.** Exact, case-sensitive Competition ID. Restricts the graph to one publicly visible Competition that exposes Contributor Network items. |
| `kind` | **Optional string.** Exact, case-sensitive discriminator: `cheatsheet`, `solver-template`, `model-reference`, or `lean-kernel-package`. |

The filters are independent and combine by intersection. A valid Competition with no active item matching `kind` returns an empty graph. When `competitionId` is omitted, the response includes items only from Competitions that are currently publicly visible and expose Contributor Network items.

Unknown query parameters, repeated parameters, blank filter values, and unsupported `kind` values return `422 RESOURCE_FIELD_INVALID`.

## Included lineage

The server first selects every active item that matches the filters. It then adds each unavailable ancestor required to preserve that active item's immutable path to its lineage root. An unavailable item with no selected active descendant is omitted.

The result is a directed forest:

- each child has at most one parent;
- every root has `lineageDepth: 0`;
- a child's `lineageDepth` is its parent's depth plus one;
- every edge stays within one Competition and one item `kind`; and
- kind-specific lineage rules continue to apply, including same-Problem ancestry for Lean Kernel packages.

Different Competitions can appear in one response, but no edge crosses a Competition boundary. The endpoint does not add synthetic Contributor Network or Competition nodes; clients may derive those presentation nodes from `competitionId` when needed.

## Example request

```bash
curl "https://api.sair.foundation/api/public/v1/contributor-network/graph?competitionId=modular-arithmetic-challenge&kind=model-reference" \
  -H "Authorization: Bearer $SAIR_API_KEY"
```

## Response

Returns `200 OK` with:

| Field | Type | Description |
| :--- | :--- | :--- |
| `nodes` | `GraphNode[]` | Selected active items and the redacted ancestors required to connect them to their lineage roots. |
| `edges` | [`GraphEdge[]`](./get-item-lineage.md#graph-edge) | Directed parent-to-child relationships whose endpoints both appear in `nodes`. |

`GraphNode` uses the [common graph-node fields and availability rules](./get-item-lineage.md#graph-node): `id`, `publicCode`, `competitionId`, `kind`, `lineageDepth`, `available`, and `directChildCount`, plus `title`, `author`, and `publishedAt` only while the item is available. Because this response has no single anchor, it does not return the item-lineage endpoint's `distanceFromAnchor` field.

Unavailable nodes return `available: false` and omit `title`, `author`, `publishedAt`, remark, kind-specific payload, favorite or comment state, and download metadata. Their structural fields remain only to preserve selected public lineage.

Treat `nodes` and `edges` as graph sets rather than relying on array order. No matches return `nodes: []` and `edges: []` with `200 OK`.

## Response limit

The 2,000-node limit is applied after required unavailable ancestors are added. The endpoint never returns a partial or silently truncated graph. If the filtered result would exceed the limit, it returns `413 GRAPH_TOO_LARGE`; narrow the Competition or kind filter, or use [Get item lineage](./get-item-lineage.md) for a depth-bounded local graph.

Successful responses use `Content-Type: application/json` and `Cache-Control: private, no-store` because item availability and direct-child counts can change.

## Errors

| HTTP | Code | When |
| :---: | :--- | :--- |
| `404` | `NOT_FOUND` | The requested Competition is unavailable or does not expose Contributor Network items. |
| `413` | `GRAPH_TOO_LARGE` | The filtered graph plus its required historical placeholders would contain more than 2,000 nodes. No partial graph is returned. |
| `422` | `RESOURCE_FIELD_INVALID` | A filter or another query parameter is invalid, unknown, or repeated. |

See [Errors](../../errors.md) for shared errors.
