> This page is for version v4 (default).
> For other versions, use one of these documentation indexes:
> - v4 (default): https://docs-beta.getzep.com/v4/llms.txt
> - v3: https://docs-beta.getzep.com/v3/llms.txt
> - v2: https://docs-beta.getzep.com/v2/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs-beta.getzep.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-beta.getzep.com/_mcp/server.

# Hyperedges

> Create, read, update, and delete hyperedges with the v4 SDKs.

A hyperedge stores one fact that relates more than two nodes. Zep stores the fact on member edges. Each member edge connects two of the nodes, and every member has the same `hyperedge_uuid`.

The hyperedge response holds shared values at the top level: `fact`, `valid_at`, `invalid_at`, `expired_at`, `created_at`, `graph_uuid`, and `uuid`. Each item in `edges` has its own `uuid`, `name`, `source_node_uuid`, and `target_node_uuid`. Zep orders the members by `uuid`.

## Add a hyperedge

Use `graph.edge.add` for a fact about one node pair. Use `graph.hyperedge.add` when the members span at least three distinct nodes.

The request needs `fact` and `edges`. Each member needs a `name`, `source_node`, and `target_node`. You can also set `valid_at`, `invalid_at`, `expired_at`, `attributes`, and `metadata`. Zep stores `attributes` on every member and attaches `metadata` to the episode created for the hyperedge.

Zep assigns the hyperedge UUID and member edge UUIDs when it accepts the task. The member edges become readable after the task completes. Use [task polling](/check-data-ingestion-status) to check completion.

**`Python`**

```python Python
from zep_cloud import EdgeNodeRef, HyperedgeInput

result = client.graph.hyperedge.add(
    graph_uuid,
    fact="Alice introduced Bob to Carol at the conference.",
    edges=[
        HyperedgeInput(
            name="INTRODUCED_TO",
            source_node=EdgeNodeRef(name="Alice"),
            target_node=EdgeNodeRef(name="Bob"),
        ),
        HyperedgeInput(
            name="INTRODUCED_TO",
            source_node=EdgeNodeRef(name="Alice"),
            target_node=EdgeNodeRef(name="Carol"),
        ),
        HyperedgeInput(
            name="MET",
            source_node=EdgeNodeRef(name="Bob"),
            target_node=EdgeNodeRef(name="Carol"),
        ),
    ],
)
```

**`TypeScript`**

```typescript TypeScript
const result = await client.graph.hyperedge.add(graphUuid, {
  fact: "Alice introduced Bob to Carol at the conference.",
  edges: [
    {
      name: "INTRODUCED_TO",
      sourceNode: { name: "Alice" },
      targetNode: { name: "Bob" },
    },
    {
      name: "INTRODUCED_TO",
      sourceNode: { name: "Alice" },
      targetNode: { name: "Carol" },
    },
    {
      name: "MET",
      sourceNode: { name: "Bob" },
      targetNode: { name: "Carol" },
    },
  ],
});
```

**`Go`**

```go Go
result, err := client.Graph.Hyperedge.Add(ctx, graphUUID, &graph.AddHyperedgeRequest{
    Fact: "Alice introduced Bob to Carol at the conference.",
    Edges: []*zep.HyperedgeInput{
        {
            Name:       "INTRODUCED_TO",
            SourceNode: &zep.EdgeNodeRef{Name: zep.String("Alice")},
            TargetNode: &zep.EdgeNodeRef{Name: zep.String("Bob")},
        },
        {
            Name:       "INTRODUCED_TO",
            SourceNode: &zep.EdgeNodeRef{Name: zep.String("Alice")},
            TargetNode: &zep.EdgeNodeRef{Name: zep.String("Carol")},
        },
        {
            Name:       "MET",
            SourceNode: &zep.EdgeNodeRef{Name: zep.String("Bob")},
            TargetNode: &zep.EdgeNodeRef{Name: zep.String("Carol")},
        },
    },
})
if err != nil {
    log.Fatal(err)
}
```

## Read hyperedges

Use `graph.hyperedge.get` to read one hyperedge. If an access policy hides any member, the API returns `404` for the whole hyperedge.

Use `graph.hyperedge.list` to read a page of hyperedges. It supports `node_uuids`, `edge_uuids`, and `episode_uuids` filters. A hyperedge matches a filter when any member matches. It must match every filter you provide. The API rejects other filters. The response has no `total_size`. Zep lists a hyperedge while it has at least one member.

## Update a hyperedge

`graph.hyperedge.update` accepts only `fact`. Zep writes the new fact to every member in one all-or-nothing update. The `name` field belongs to each member. If you change `fact` with `graph.edge.update` on one member, Zep updates the fact on every member.

## Change hyperedge membership

Use `graph.hyperedge.create_edge` to add one member. Set only `name`, `source_node`, and `target_node`. Use an upper-snake-case value for `name`. The new member inherits the hyperedge's fact, timestamps, and episodes.

Use `graph.hyperedge.delete_edge` to remove one member. Deleting the last member removes the hyperedge. Use `graph.hyperedge.delete` to delete every member.

## Retrieve hyperedge facts

`graph.get_context` writes each hyperedge fact once in the context block.

## Extract hyperedges from episodes

Zep enables hyperedge extraction from episodes for each account. Contact Zep to enable it. You can use the hyperedge API without episode extraction.