Knowledge Graph Endpoints
Entity CRUD, graph queries, context assembly, and impact analysis. The knowledge-graph-service runs on port 8003 and is proxied through the API gateway at http://localhost:8000.
Raw graph operations (entities, edges, context, template query, seed) are
reached through the gateway under the /api/v1/graph/ prefix, which the
gateway rewrites to the service’s bare path (/api/v1/graph/entities/Well/x
→ /entities/Well/x). Impact analysis is a separate /api/v1/impact/
prefix. The runtime DB-backed managed entities are a distinct surface at
/api/v1/entities (see below) — do not confuse them with the raw AGE
vertices documented here.
Endpoints
| Method | Gateway Path | Description |
|---|---|---|
POST | /api/v1/graph/entities | Create a graph entity (AGE vertex) |
GET | /api/v1/graph/entities/{label} | List entities by label |
GET | /api/v1/graph/entities/{label}/{id} | Get a specific entity |
PUT | /api/v1/graph/entities/{label}/{id} | Update an entity |
DELETE | /api/v1/graph/entities/{label}/{id} | Delete an entity |
PUT | /api/v1/graph/entities/Well/{id}/production | Update well production data |
POST | /api/v1/graph/edges | Create a relationship |
GET | /api/v1/graph/edges/{label}/{id} | Get entity relationships |
POST | /api/v1/graph/query-template | Run a whitelisted graph-query template ({template_id, params}) |
GET | /api/v1/graph/context/{well_api} | Assemble context for a well |
GET | /api/v1/graph/context/managed/{id} | Assemble context for a managed entity |
GET | /api/v1/impact/{label}/{id} | Bidirectional impact analysis |
GET | /api/v1/impact/outward/{label}/{id} | Outward impact propagation |
GET | /api/v1/impact/inward/{label}/{id} | Inward impact propagation |
GET | /api/v1/impact/tree | Infrastructure tree |
POST | /api/v1/graph/seed | Seed demo data |
The service’s raw-Cypher POST /query endpoint is not routed through the
gateway — /api/v1/graph/query returns 404 by design (spec D5,
injection-prone). Only the parameterized template form
(/api/v1/graph/query-template) is publicly reachable.
This is an oil & gas (RRC vertical) graph today — the default AGE graph is
oilgas and the vertex labels below are O&G entities — but the entity/edge and
context APIs are domain-neutral.
Entity CRUD
POST /api/v1/graph/entities
Create a new entity vertex in the knowledge graph.
curl -X POST http://localhost:8000/api/v1/graph/entities \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "Well",
"properties": {
"entity_id": "well-new-001",
"well_name": "Smith Ranch #4",
"api_number": "42-383-67890",
"operator": "Permian Energy Inc.",
"status": "drilling",
"latitude": 31.9523,
"longitude": -102.1245
}
}'Valid labels: Well, Lease, Field, Formation, Operator, Permit, FlaringAuthorization, FlaringEvent, InfrastructureProject, Regulation, Wellpad, Facility, PipelineRoute, WellEvent, ComplianceDeadline, FilingPackage, WellConversation, Project, Equipment, Pipeline.
GET /api/v1/graph/entities/{label}
List all entities of a given type.
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8000/api/v1/graph/entities/Well"GET /api/v1/graph/entities/{label}/{entity_id}
Get a specific entity by label and ID.
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8000/api/v1/graph/entities/Well/well-001Managed entities (/api/v1/entities) are the horizontalization-era,
runtime DB-backed entity records keyed by entity-type definition (admin UI at
/configuration/entity-types). They are served by the same service but under
a separate gateway route (/api/v1/entities → /managed-entities), with
entity-type listings at /api/v1/entity-types and relationship schemas at
/api/v1/relationship-types / /api/v1/relationship-rules (public reads).
Relationships
POST /api/v1/graph/edges
Create a relationship between two entities.
curl -X POST http://localhost:8000/api/v1/graph/edges \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from_label": "Well",
"from_id": "well-001",
"to_label": "Lease",
"to_id": "lease-001",
"edge_label": "LOCATED_IN",
"properties": {}
}'GET /api/v1/graph/edges/{label}/{entity_id}
Get all relationships for an entity.
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8000/api/v1/graph/edges/Well/well-001?direction=out"Context Assembly
R34 Phase 4 unified both endpoints onto a single tenant-scoped graph walk (the
context_assemble capability). The neighborhood traversal is one
TenantScopedConnection round trip that returns each neighbor’s properties inline
— no per-neighbor re-fetch, no default-graph dependency, no hardcoded per-section
Cypher.
GET /api/v1/graph/context/managed/{entity_id}
The context_assemble capability. Returns two views from one walk:
structured— anEntityContext: complete (every field; relationships by edge label, up to a 1000-per-relationship sanity ceiling). Consumed by the rules/governance layer.context_text— a truncated view for the LLM context window: a per-relationship cap (default 25) with explicit"…and N more … not shown"overflow markers, an 8K-token backstop (tiktoken cl100k_baseproxy), and the domain-filtered significant/plain field split.
{entity_id} may be the AGE vertex uuid (what entity_resolve returns) or
the business entity_id — the walk anchors on either. context_text and the
R27 back-compat counts (fields_highlighted, detection_results_included,
token_estimate, entities_referenced) stay top-level alongside the new
structured / truncation_occurred / relationships_truncated fields.
Query params: entity_type_key (required), domain_tags (comma-separated),
depth (default 1 — R34 groups first-hop), max_per_relationship (default 25),
max_tokens (default 8000), tenant_id.
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8000/api/v1/graph/context/managed/well-001?entity_type_key=well&domain_tags=compliance"GET /api/v1/graph/context/{well_api}
Legacy well-centric context by API number (RRC vertical). R34 Phase 4 rewrote
this as a thin adapter over the context_assemble capability: it resolves
well_api → entity through the same tenant-scoped walk, then maps the result back
into the legacy sections shape the hardcoded Rule 37/32 tools still read. No more
api_number f-string on the default graph.
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8000/api/v1/graph/context/42-383-12345Graph Query
POST /api/v1/graph/query-template
Run a whitelisted graph query. R34 Phase 1 replaced the injection-prone raw-Cypher
contract with a named-template registry: callers send a template_id plus param
values (never Cypher). The request is resolved against the server-side whitelist
(graph_query_templates) and executed through a TenantScopedConnection, so every query
is tenant-scoped and injection-safe. (Through the gateway this is
/api/v1/graph/query-template, rewritten to the service path /query/template.)
curl -X POST "http://localhost:8000/api/v1/graph/query-template?tenant_id=00000000-0000-0000-0000-000000000001" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"template_id": "operator_wells",
"params": {"operator_id": "OP-0001"}
}'tenant_id is an optional query parameter (default: the dev tenant
00000000-0000-0000-0000-000000000001); it selects the per-tenant AGE graph namespace.
Registered templates:
template_id | Params (kind) | Returns | Columns |
|---|---|---|---|
operator_wells | operator_id (value) | Wells operated by an operator | w |
operator_permits | operator_id (value) | Permits for an operator | p |
operator_flaring_auths | operator_id (value) | Flaring authorizations for an operator | fa |
operator_flaring_auths_via_lease | operator_id (value) | Flaring auths reached via the operator’s leases | fa |
edge_usage | edge_label (label) | Source/target/count usage for a relationship type | source, target, cnt |
Param kinds determine validation:
- value params (e.g.
operator_id) are escaped viaescape_cypher_stringand interpolated as quoted literals. - label params (e.g.
edge_label) are whitelist-validated againstEDGE_LABELS/VERTEX_LABELSand substituted raw — AGE cannot bind or escape a relationship type, so a value outside the whitelist is rejected (400), never substituted.
Errors return 400: unknown template_id, a param set that doesn’t exactly match the
template, or a non-whitelisted label.
The response shape is { "results": [ ... ], "count": N } keyed by the template’s columns.
Raw Cypher is not publicly reachable. The service still implements a
legacy POST /query body ({ "query": "<cypher>", "columns": [...] }) for
internal service-to-service callers, but the gateway hard-404s
/api/v1/graph/query (spec D5). New callers — internal or external — must use
the template_id form.
Impact Analysis
GET /api/v1/impact/{label}/{entity_id}
Bidirectional impact analysis — find all entities affected by changes to a given entity.
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8000/api/v1/impact/Well/well-001GET /api/v1/impact/tree
Get the infrastructure tree showing hierarchical relationships.
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8000/api/v1/impact/tree?root_label=Wellpad&root_id=pad-001"POST /api/v1/graph/seed
Seed the knowledge graph with demo data.
curl -X POST http://localhost:8000/api/v1/graph/seed \
-H "Authorization: Bearer $TOKEN"This endpoint is for development only. It creates sample wells, leases, fields, operators, and relationships.