SapixDBSapixDB/Docs
Home

Manual · Graph

Graph Index

✓ Shipped

SapixDB maintains a separate graph layer that stores typed directional edges between agents. Graph edges describe the structureof your data model — which agents relate to which — independently of the records stored in each agent's strand.

ℹ Graph edges vs. multi-agent joinsGraph edges are structural, schema-level links. They declare that one agent type relates to another and carry optional metadata about the relationship. They do not match individual records.

Multi-agent joins are data-level field matches. A join query scans the records of two agents at query time and pairs rows that share a field value.

Use graph edges to model your data hierarchy and drive traversal. Use joins when you need to correlate specific record values across agents. The two features are complementary.

Creating an edge

An edge is a directional, typed link from one agent to another. The edge_type is a free-form string you define — it describes the nature of the relationship.

HTTP
POST /v1/graph/edges
Authorization: Bearer spx_root_YOUR_ROOT_KEY
Content-Type: application/json

{
  "from_agent": "users",
  "to_agent":   "orders",
  "edge_type":  "has_orders",
  "meta": {
    "established": "2026-07-09"
  }
}
FieldRequiredDescription
from_agentYesAgent ID the edge originates from.
to_agentYesAgent ID the edge points to.
edge_typeYesA label describing the relationship (e.g. "has_orders", "belongs_to").
metaNoArbitrary JSON object stored alongside the edge.

Listing edges

Edges from an agent

HTTP
GET /v1/graph/edges?from=users
Authorization: Bearer spx_root_YOUR_ROOT_KEY

Returns all edges where from_agent is users — i.e. everything that users points to.

JSON response
{
  "edges": [
    {
      "from_agent": "users",
      "to_agent":   "orders",
      "edge_type":  "has_orders",
      "meta": { "established": "2026-07-09" }
    },
    {
      "from_agent": "users",
      "to_agent":   "profiles",
      "edge_type":  "has_profile",
      "meta": {}
    }
  ]
}

Edges to an agent

HTTP
GET /v1/graph/edges?to=orders
Authorization: Bearer spx_root_YOUR_ROOT_KEY

Returns all edges where to_agent is orders — i.e. which agents point to orders.

Deleting an edge

Delete a specific edge by specifying the from agent, to agent, and edge type in the URL path:

HTTP
DELETE /v1/graph/edges/users/orders/has_orders
Authorization: Bearer spx_root_YOUR_ROOT_KEY

Returns 204 No Content on success. Deleting an edge does not affect records stored in either agent.

Graph traversal

Traversal follows edges outward from a starting agent up to a specified hop depth. It returns all agents reachable within that depth along with the edge types connecting them.

HTTP
GET /v1/graph/traverse?from=users&depth=2
Authorization: Bearer spx_root_YOUR_ROOT_KEY
JSON response
{
  "origin": "users",
  "depth":  2,
  "nodes": [
    { "agent": "orders",    "via": "has_orders",    "hops": 1 },
    { "agent": "profiles",  "via": "has_profile",   "hops": 1 },
    { "agent": "shipments", "via": "has_shipments",  "hops": 2 }
  ]
}

With depth=2, the traversal visits direct neighbours (1 hop) and their neighbours (2 hops). Increasing depth follows longer paths but may return a large result set on densely connected graphs.

⚠ Traversal is breadth-firstTraversal visits each reachable agent once. If multiple paths lead to the same agent, it appears once in nodes at the shortest hop distance.

Record-level links

Edges can be scoped to specific records within agents by supplying from_record and to_record content hashes. This creates a link between individual records rather than between agents as a whole.

HTTP
POST /v1/graph/edges
Authorization: Bearer spx_root_YOUR_ROOT_KEY
Content-Type: application/json

{
  "from_agent":  "users",
  "to_agent":    "orders",
  "edge_type":   "placed",
  "from_record": "usr_hash_b3a7c2...",
  "to_record":   "order_hash_9d2e4f...",
  "meta": {
    "amount": 299.99
  }
}
FieldDescription
from_recordContent hash of the source record within from_agent.
to_recordContent hash of the target record within to_agent.

Record-level links are stored in the same graph layer as agent-level edges. They appear in GET /v1/graph/edges responses alongside agent-level edges. Traversal at depth=1 from an agent returns all agents it has edges to, regardless of whether those edges are record-level or agent-level.

Worked example — company hierarchy

Model a three-level hierarchy: a company has departments, and departments have employees.

Step 1 — create the edges

company → departments
POST /v1/graph/edges
{
  "from_agent": "company",
  "to_agent":   "departments",
  "edge_type":  "has_departments"
}
departments → employees
POST /v1/graph/edges
{
  "from_agent": "departments",
  "to_agent":   "employees",
  "edge_type":  "has_employees"
}

Step 2 — traverse from company at depth 2

HTTP
GET /v1/graph/traverse?from=company&depth=2
JSON response
{
  "origin": "company",
  "depth":  2,
  "nodes": [
    { "agent": "departments", "via": "has_departments", "hops": 1 },
    { "agent": "employees",   "via": "has_employees",   "hops": 2 }
  ]
}

Step 3 — link a specific employee to a specific department

Record-level link
POST /v1/graph/edges
{
  "from_agent":  "departments",
  "to_agent":    "employees",
  "edge_type":   "member",
  "from_record": "dept_hash_e4a1b2...",
  "to_record":   "emp_hash_7f3c9d...",
  "meta": { "joined": "2025-03-15" }
}

API reference

MethodPathAction
POST/v1/graph/edgesCreate an agent-level or record-level edge.
GET/v1/graph/edges?from=:agentList all edges originating from an agent.
GET/v1/graph/edges?to=:agentList all edges pointing to an agent.
DELETE/v1/graph/edges/:from/:to/:typeDelete a specific edge by from, to, and type.
GET/v1/graph/traverse?from=:agent&depth=:nBreadth-first traversal from an agent up to depth n.
ℹ Direct edge access requires admin:graphPOST/GET /v1/graph/edges and DELETE /v1/graph/edges/:src/:type/:dst require the root key or a scoped key holding admin:graph — distinct from the row-policy-filtered refs routes and from GET /v1/graph/traverse, which stay ordinary reads. Creating/deleting an edge directly reveals or changes structural links between agents platform-wide, so it's treated the same as other cluster-wide config, not a per-tenant read/write.

Known Limitations

1-hop neighbors only (direct API)
neighbors_out / neighbors_in return direct neighbors. Use GET /v1/graph/traverse?depth=N for multi-hop BFS. The traverse endpoint is the recommended path for graph walks.
No referential integrity
Deleting an agent node does not cascade to its edges or record refs. The application layer is responsible for cleanup. This matches the design intent: agents are autonomous and deletion is rare.
No cycle detection on traversal
If your graph contains cycles, set depth to a finite value. Unbounded traversal on a cyclic graph will not loop forever (depth caps it) but may return more nodes than intended.
Single writer per process
GraphIndex owns the underlying store exclusively. Multi-process write access is not supported. Use a single owner process with shared concurrent readers.