# Graph API Status: Draft (2025-11-26) — aligns with Sprint 0207 Graph API implementation (in-memory seed; RBAC + budgets enforced). Base URL: `/api/graph` (examples use relative paths). ## Common headers - `X-Stella-Tenant` (required) - `Authorization: Bearer ` (required) - `X-Stella-Scopes`: space/comma/semicolon separated scopes - `/graph/search`: `graph:read` or `graph:query` - `/graph/query|paths|diff`: `graph:query` - `/graph/export`: `graph:export` Content-Type for requests: `application/json` Streaming responses: `application/x-ndjson` ## POST /graph/search Returns NDJSON stream of tiles (`node`, optional `cursor`). Body: ```json { "kinds": ["component", "artifact"], "query": "pkg:npm/", "filters": { "ecosystem": "npm" }, "limit": 50, "cursor": "opaque" } ``` Errors: - 400 `GRAPH_VALIDATION_FAILED` (missing kinds/query/filters) - 401 missing auth; 403 missing scopes ## POST /graph/query Streams nodes, edges (optional), stats, cursor with cost metadata. Body: ```json { "kinds": ["component"], "query": "widget", "filters": { "tenant": "acme" }, "includeEdges": true, "includeStats": true, "includeOverlays": true, "limit": 100, "cursor": "opaque", "budget": { "tiles": 6000, "nodes": 5000, "edges": 10000 } } ``` Error tile if edge budget exceeded: `{ "type":"error","data":{"error":"GRAPH_BUDGET_EXCEEDED",...}}` ## POST /graph/paths Finds paths up to depth 6 between sources/targets. Body: ```json { "sources": ["gn:acme:component:one"], "targets": ["gn:acme:component:two"], "kinds": ["depends_on"], "maxDepth": 4, "includeOverlays": false, "budget": { "tiles": 2000, "nodes": 1500, "edges": 3000 } } ``` Response: NDJSON tiles (`node`, `edge`, `stats`, `cursor`). ## POST /graph/diff Diff two snapshots. Body: ```json { "snapshotA": "snapA", "snapshotB": "snapB", "includeEdges": true, "includeStats": true, "budget": { "tiles": 2000 } } ``` Response tiles: `node`/`edge` with change types, `stats`, optional `cursor`. ## POST /graph/export Kicks off an in-memory export job and returns manifest. Body: ```json { "format": "ndjson", // ndjson|csv|graphml|png|svg "includeEdges": true, "snapshotId": "snapA", // optional "kinds": ["component"], // optional "query": "pkg:", // optional "filters": { "ecosystem": "npm" } } ``` Response: ```json { "jobId": "job-123", "status": "completed", "format": "ndjson", "sha256": "...", "size": 1234, "downloadUrl": "/graph/export/job-123", "completedAt": "2025-11-26T00:00:00Z" } ``` Download: `GET /graph/export/{jobId}` (returns file, headers include `X-Content-SHA256`). ## Health `GET /healthz` → 200 when service is ready; no auth/scopes required. ## Error envelope ```json { "error": "GRAPH_VALIDATION_FAILED", "message": "details", "requestId": "optional" } ``` ## Notes - All timestamps UTC ISO-8601. - Ordering is deterministic; cursors are opaque base64 offsets. - Overlays use `policy.overlay.v1` and `openvex.v1` payloads. Budgeted tiles reserve room for cursors when `hasMore` is true.