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.
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /entities | Create a graph entity |
GET | /entities/{label} | List entities by label |
GET | /entities/{label}/{id} | Get a specific entity |
PUT | /entities/{label}/{id} | Update an entity |
DELETE | /entities/{label}/{id} | Delete an entity |
PUT | /entities/Well/{id}/production | Update well production data |
POST | /edges | Create a relationship |
GET | /edges/{label}/{id} | Get entity relationships |
POST | /query | Run a whitelisted graph-query template ({template_id, params}); legacy raw Cypher deprecated |
GET | /context/assemble/{well_api} | Assemble context for a well |
GET | /context/assemble/managed/{id} | Assemble context for managed entity |
GET | /impact/{label}/{id} | Bidirectional impact analysis |
GET | /impact/outward/{label}/{id} | Outward impact propagation |
GET | /impact/inward/{label}/{id} | Inward impact propagation |
GET | /impact/tree | Infrastructure tree |
POST | /seed | Seed demo data |
Entity CRUD
POST /entities
Create a new entity vertex in the knowledge graph.
curl -X POST http://localhost:8000/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 /entities/{label}
List all entities of a given type.
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8000/entities/Well"GET /entities/{label}/{entity_id}
Get a specific entity by label and ID.
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8000/entities/Well/well-001Relationships
POST /edges
Create a relationship between two entities.
curl -X POST http://localhost:8000/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 /edges/{label}/{entity_id}
Get all relationships for an entity.
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8000/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 /context/assemble/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/context/assemble/managed/well-001?entity_type_key=well&domain_tags=compliance"GET /context/assemble/{well_api}
Legacy well-centric context by API number. 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 (R35 deletes the adapter
and those tools together). No more api_number f-string on the default graph.
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8000/context/assemble/42-383-12345Graph Query
POST /query
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.
curl -X POST "http://localhost:8000/query?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 unchanged — { "results": [ ... ], "count": N } keyed by the
template’s columns.
Deprecated — raw Cypher form. The legacy body { "query": "<cypher>", "columns": [...] }
is still accepted but logs a deprecation warning. It remains only because the
orchestration-engine and the 35-skill query layer still send raw Cypher to this endpoint;
migrating them onto the template registry and removing the raw branch is R35 work, not
Phase 1. New callers must use template_id.
Impact Analysis
GET /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/impact/Well/well-001GET /impact/tree
Get the infrastructure tree showing hierarchical relationships.
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8000/impact/tree?root_label=Wellpad&root_id=pad-001"POST /seed
Seed the knowledge graph with demo data.
curl -X POST http://localhost:8000/seed \
-H "Authorization: Bearer $TOKEN"This endpoint is for development only. It creates sample wells, leases, fields, operators, and relationships.