{"openapi":"3.0.3","info":{"title":"CodeGraph API","description":"Dependency graph API for Success IT's full-stack product suite. Maps Angular and React frontends → C#/Node APIs → Stored Procedures → SQL Server Tables → JasperReports → Legacy VBA and PowerBuilder. Use this API to query cross-layer impact before making changes.\n\n**Products indexed**: iris, workshop, car, hire_purchase, expat_furniture, expat_delivery, successsql, cfreight, dms, platform, sirsql, pioneer, sensatec, techron, lsjlytox, freight_legacy.\n\n**Layers**: angular, react, csharp, node, sql, jasper, vba, powerbuilder.\n\n**Node keys** are product-scoped for application and legacy layers and database-qualified for SQL. Examples: `iris:angular:QuotationProfileComponent`, `iris:endpoint:/api/quotation`, `table:GI.dbo.tblCustomer`, `proc:GI.dbo.wmQotToPolicy`, `iris:jasper:rptPolicy`, and `car:vba_form:frmQuotation`.\n\nAuthenticated routes accept X-Api-Key (per-client keys via CODEGRAPH_API_KEYS) or an Azure AD bearer token. Analytical routes expose bounded results with classification, freshness, completeness, diagnostics, and provenance. MCP is an optional adapter over the same application service; REST is the primary integration contract.","version":"1.0.0"},"servers":[{"url":"/","description":"Current server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"Per-client key from CODEGRAPH_API_KEYS (\"label:key,...\"), one per teammate/agent, each independently revocable. Legacy CODEGRAPH_API_KEY also accepted."},"AzureADBearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Azure AD (Entra ID) RS256 token with the app's client audience. Active only when AZURE_TENANT_ID and AZURE_CLIENT_ID are configured."}},"schemas":{"Node":{"type":"object","properties":{"node_key":{"type":"string","description":"Unique key with layer prefix","example":"iris:angular:APDNCNComponent"},"name":{"type":"string","example":"APDNCNComponent"},"node_type":{"type":"string","description":"Layer-specific node type; the set expands as indexers are added.","example":"component"},"layer":{"type":"string","enum":["angular","react","csharp","node","sql","jasper","vba","powerbuilder"],"example":"angular"},"product":{"type":"string","enum":["iris","workshop","car","hire_purchase","expat_furniture","expat_delivery","successsql","cfreight","dms","platform","sirsql","pioneer","sensatec","techron","lsjlytox","freight_legacy"],"example":"iris"},"file_path":{"type":"string","nullable":true,"example":"app/views/accounting/apdncn.component.ts"},"metadata":{"type":"string","nullable":true,"description":"JSON string with extra context (e.g. route, httpMethod, parameters)"}}},"TraceNode":{"type":"object","description":"A node found during graph traversal with depth and path info","properties":{"node_key":{"type":"string","example":"iris:angular:AmplitudeService"},"name":{"type":"string","example":"AmplitudeService"},"node_type":{"type":"string","example":"service"},"layer":{"type":"string","example":"angular"},"file_path":{"type":"string","nullable":true},"depth":{"type":"integer","description":"Hops from the center node","example":1},"path_names":{"type":"string","description":"Human-readable traversal path","example":"APDNCNComponent → AmplitudeService"},"via_edge":{"type":"string","description":"Edge type used to reach this node","example":"injects"}}},"Edge":{"type":"object","properties":{"source":{"type":"string","example":"iris:angular:APDNCNComponent"},"source_name":{"type":"string","example":"APDNCNComponent"},"source_type":{"type":"string","example":"component"},"source_layer":{"type":"string","example":"angular"},"target":{"type":"string","example":"iris:angular:AmplitudeService"},"target_name":{"type":"string","example":"AmplitudeService"},"target_type":{"type":"string","example":"service"},"target_layer":{"type":"string","example":"angular"},"edge_type":{"type":"string","example":"injects"},"confidence":{"type":"number","description":"1.0=certain, 0.7=regex, 0.5=heuristic","example":1}}},"IndexRun":{"type":"object","properties":{"indexer":{"type":"string","enum":["sql-server","csharp","angular","react","azure-functions-ts","jrxml","vba","powerbuilder"],"example":"sql-server"},"product":{"type":"string","example":"iris"},"status":{"type":"string","enum":["running","completed","failed"],"example":"completed"},"started_at":{"type":"string","example":"2026-03-15 14:57:00"},"finished_at":{"type":"string","nullable":true,"example":"2026-03-15 14:57:53"},"node_count":{"type":"integer","example":1637},"edge_count":{"type":"integer","example":2376},"error_msg":{"type":"string","nullable":true}}},"SearchResult":{"type":"object","properties":{"score":{"type":"number","description":"Relevance score (higher is better)","example":80},"node_key":{"type":"string"},"name":{"type":"string"},"node_type":{"type":"string"},"layer":{"type":"string"},"product":{"type":"string"},"file_path":{"type":"string","nullable":true}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}},"Envelope":{"type":"object","description":"The one wire shape for every query endpoint (REST and MCP tools alike). HTTP status mirrors the classification: 200 PASS, 203 DEGRADED, 300 AMBIGUOUS, 404 BLOCKED, 503 UNAVAILABLE. The X-CodeGraph-Classification header carries it too.","properties":{"tool":{"type":"string","example":"codegraph_blast"},"classification":{"type":"string","enum":["PASS","DEGRADED","BLOCKED","UNAVAILABLE","AMBIGUOUS","FAIL"],"description":"PASS = answerable and current. DEGRADED = answerable but visibly qualified (stale index, fuzzy match, expected-ref mismatch, truncation). BLOCKED = nothing to answer (unknown node/product). UNAVAILABLE = structurally cannot answer (layer not indexed, blind counterpart). AMBIGUOUS = name spans products; per-product counts only."},"answer":{"type":"object","description":"Tool-specific payload"},"match":{"type":"object","properties":{"mode":{"type":"string","enum":["exact","fuzzy","search","none","ambiguous"]},"products":{"type":"array","items":{"type":"string"}},"excluded_near_misses":{"type":"array","items":{"type":"object"}}}},"provenance":{"type":"object","properties":{"products":{"type":"array","items":{"type":"string"}},"threshold_days":{"type":"integer"},"oldest_age_days":{"type":"integer","nullable":true},"indexes":{"type":"array","items":{"type":"object","properties":{"product":{"type":"string"},"indexer":{"type":"string"},"last_indexed":{"type":"string","nullable":true},"age_days":{"type":"integer","nullable":true},"git_ref":{"type":"string","nullable":true,"example":"origin/dev@e5f6a7b"},"stale":{"type":"boolean"}}}}}},"capability":{"type":"object","nullable":true,"description":"blast-family only: upstream/downstream verdicts and gaps (see lib/capabilities.js)"},"freshness":{"type":"object","properties":{"stale_warnings":{"type":"array","items":{"type":"string"}},"fresh_affirmations":{"type":"array","items":{"type":"string"}}}},"truncated":{"type":"boolean"},"allow_stale_used":{"type":"boolean","description":"Caller opted in; the classification is still DEGRADED — opting in never launders a stale answer"},"allow_fuzzy_used":{"type":"boolean"},"diagnostics":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","example":"STALE_INDEX"},"message":{"type":"string"}}}}}}},"parameters":{"Product":{"name":"product","in":"query","description":"Scope the query to one product. Without it, a name matching several products returns AMBIGUOUS with per-product counts.","schema":{"type":"string"}},"Depth":{"name":"depth","in":"query","description":"Traversal depth (default 10)","schema":{"type":"integer","default":10}},"AllProducts":{"name":"all_products","in":"query","description":"Explicitly accept a cross-product union instead of an AMBIGUOUS answer (1/true)","schema":{"type":"string","enum":["1","true"]}},"AllowStale":{"name":"allow_stale","in":"query","description":"Serve the DEGRADED (stale) answer instead of treating it as an error. The response stays visibly DEGRADED.","schema":{"type":"string","enum":["1","true"]}},"AllowFuzzy":{"name":"allow_fuzzy","in":"query","description":"Accept a substring match as an answer instead of classifying it DEGRADED (1/true)","schema":{"type":"string","enum":["1","true"]}},"ExpectedRef":{"name":"expected_ref","in":"query","description":"Ref the caller is reviewing (e.g. origin/dev). A mismatch with the indexed ref classifies the answer DEGRADED.","schema":{"type":"string"}},"ExpectedSha":{"name":"expected_sha","in":"query","description":"Commit sha the caller is reviewing. A mismatch classifies the answer DEGRADED.","schema":{"type":"string"}},"RequiredLayers":{"name":"required_layers","in":"query","description":"Comma-separated layers that must be indexed (e.g. sql,angular). Any missing layer classifies UNAVAILABLE.","schema":{"type":"string","example":"sql,angular"}},"DirectEdgeLimit":{"name":"limit","in":"query","description":"Maximum direct inbound and outbound connections returned per direction (default and maximum 1000). Totals and explicit truncation diagnostics are always returned.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1000}}}},"paths":{"/api/health":{"get":{"summary":"Health check","description":"Returns server health, uptime, database statistics, and index freshness. No authentication required. Status is derived from index provenance — a stale snapshot reports degraded/stale, never a hard-coded healthy.","security":[],"responses":{"200":{"description":"Server health (status reflects index freshness, not just liveness)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","stale","unknown","unhealthy"],"description":"healthy = no stale indexes; degraded = some stale; stale = every index past threshold; unknown = no index runs recorded; unhealthy = server error."},"total_nodes":{"type":"integer","example":7156},"total_edges":{"type":"integer","example":14792},"db_size_bytes":{"type":"integer","example":3092480},"uptime_seconds":{"type":"integer","example":86400},"index_freshness":{"type":"object","properties":{"threshold_days":{"type":"integer","example":7},"total":{"type":"integer","description":"Product x indexer rows with a completed run"},"stale_count":{"type":"integer"},"oldest_age_days":{"type":"integer","nullable":true},"stale":{"type":"array","items":{"type":"object","properties":{"product":{"type":"string","example":"iris"},"indexer":{"type":"string","example":"angular"},"age_days":{"type":"integer","example":50},"last_indexed":{"type":"string","nullable":true},"git_ref":{"type":"string","nullable":true,"example":"origin/dev@abcdef1"}}}}}}}}}}}}}},"/api/stats":{"get":{"summary":"Graph summary statistics","description":"Returns total node/edge counts, breakdowns by type and layer, and recent index runs. Good first call to understand what's in the graph.","responses":{"200":{"description":"Graph statistics","content":{"application/json":{"schema":{"type":"object","properties":{"total_nodes":{"type":"integer","example":7156},"total_edges":{"type":"integer","example":14792},"nodes_by_type":{"type":"array","items":{"type":"object","properties":{"node_type":{"type":"string"},"layer":{"type":"string"},"count":{"type":"integer"}}}},"edges_by_type":{"type":"array","items":{"type":"object","properties":{"edge_type":{"type":"string"},"count":{"type":"integer"}}}},"recent_index_runs":{"type":"array","items":{"$ref":"#/components/schemas/IndexRun"}}}}}}}}}},"/api/status":{"get":{"summary":"Indexing status","description":"Returns the most recent index run for each product and indexer type. Use this to check when data was last refreshed.","responses":{"200":{"description":"Index run status","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"last_runs":{"type":"array","items":{"$ref":"#/components/schemas/IndexRun"}}}}}}}}}},"/api/search":{"get":{"summary":"Search nodes (envelope)","description":"Search nodes by name or node_key substring, ranked by relevance score, with total match count and truncation flag. Returns the standard envelope; a truncated page is DEGRADED (203), never silently cut.","parameters":[{"name":"q","in":"query","required":true,"description":"Search term (matches name and node_key)","schema":{"type":"string"},"example":"RenewPolicy"},{"name":"type","in":"query","description":"Filter by node_type","schema":{"type":"string","enum":["component","service","route","function","endpoint","class","method","stored_procedure","table","view","jasper_report","vba_module","vba_form","vba_report","vba_query","vba_table"]}},{"name":"layer","in":"query","description":"Filter by layer","schema":{"type":"string","enum":["angular","react","csharp","node","sql","jasper","vba","powerbuilder"]}},{"$ref":"#/components/parameters/Product"},{"name":"limit","in":"query","description":"Max results (default 25)","schema":{"type":"integer","default":25}}],"responses":{"200":{"description":"Ranked search results (complete page)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"203":{"description":"Truncated page — answer.results is partial, answer.total holds the real count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"404":{"description":"Missing query parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}}},"/api/blast/{key}":{"get":{"summary":"Blast radius / impact analysis","description":"The most important endpoint for impact assessment. Returns all nodes affected upstream (what breaks if I change this) and downstream (what does this depend on) from a given node, traversing the full dependency graph recursively. Use this before making changes to stored procedures, API endpoints, or tables.","parameters":[{"name":"key","in":"path","required":true,"description":"Full product-scoped or database-qualified node_key to analyze","schema":{"type":"string"},"example":"table:GI.dbo.tblCustomer"},{"name":"depth","in":"query","description":"Max traversal depth (default 10)","schema":{"type":"integer","default":10}}],"responses":{"200":{"description":"Full impact analysis","content":{"application/json":{"schema":{"type":"object","properties":{"center":{"type":"string","description":"The node_key being analyzed"},"upstream":{"type":"array","description":"Nodes that depend on this (what breaks if changed). Sorted by depth.","items":{"$ref":"#/components/schemas/TraceNode"}},"downstream":{"type":"array","description":"Nodes this depends on (what this uses). Sorted by depth.","items":{"$ref":"#/components/schemas/TraceNode"}},"total_affected":{"type":"integer","description":"Total unique nodes in the blast radius (excluding center)"}}}}}}}}},"/api/upstream/{key}":{"get":{"summary":"What breaks if I change this? (envelope)","description":"Everything that depends on the node. Same envelope, params, and classifications as /api/blast, scoped to the upstream direction.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Depth"},{"$ref":"#/components/parameters/Product"},{"$ref":"#/components/parameters/AllProducts"},{"$ref":"#/components/parameters/AllowStale"},{"$ref":"#/components/parameters/ExpectedRef"},{"$ref":"#/components/parameters/RequiredLayers"}],"responses":{"200":{"description":"PASS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"203":{"description":"DEGRADED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"300":{"description":"AMBIGUOUS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"404":{"description":"BLOCKED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"503":{"description":"UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}}},"/api/downstream/{key}":{"get":{"summary":"What does this depend on? (envelope)","description":"Everything the node depends on. Same envelope, params, and classifications as /api/blast, scoped to the downstream direction.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Depth"},{"$ref":"#/components/parameters/Product"},{"$ref":"#/components/parameters/AllProducts"},{"$ref":"#/components/parameters/AllowStale"},{"$ref":"#/components/parameters/ExpectedRef"},{"$ref":"#/components/parameters/RequiredLayers"}],"responses":{"200":{"description":"PASS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"203":{"description":"DEGRADED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"300":{"description":"AMBIGUOUS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"404":{"description":"BLOCKED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"503":{"description":"UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}}},"/api/context/{key}":{"get":{"summary":"360-degree view of a node (envelope)","description":"Node identity, metadata, and all inbound/outbound edges. A name matching several products is AMBIGUOUS with candidates rather than a silently-chosen first match.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Product"},{"$ref":"#/components/parameters/AllowStale"},{"$ref":"#/components/parameters/ExpectedRef"},{"$ref":"#/components/parameters/DirectEdgeLimit"}],"responses":{"200":{"description":"PASS / DEGRADED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"203":{"description":"DEGRADED — fuzzy match or stale provenance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"300":{"description":"AMBIGUOUS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"404":{"description":"BLOCKED — node not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}}},"/api/table/{name}":{"get":{"summary":"What code touches this table? (envelope)","description":"Dependents of a table/view with per-product counterpart-layer coverage. A product whose stored procedures have no table edges is UNAVAILABLE for that layer — the list cannot be complete there. Zero dependents is BLOCKED, never 'unused'.","parameters":[{"name":"name","in":"path","required":true,"description":"Table or view name (exact first, substring fallback is reported as fuzzy)","schema":{"type":"string"}},{"$ref":"#/components/parameters/Product"},{"$ref":"#/components/parameters/AllowStale"},{"$ref":"#/components/parameters/AllowFuzzy"},{"$ref":"#/components/parameters/ExpectedRef"}],"responses":{"200":{"description":"PASS / DEGRADED with coverage verdicts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"203":{"description":"DEGRADED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"404":{"description":"BLOCKED — no dependents in the graph (not evidence of unused)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"503":{"description":"UNAVAILABLE — blind counterpart layer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}}},"/api/consumers/{name}":{"get":{"summary":"Angular template consumers + @Input bindings (envelope)","description":"Which components render a component, which modules declare it, and which @Input bindings each call site passes. Zero renders consumers is UNAVAILABLE (the product's index may predate template indexing), never a clean zero.","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Product"},{"name":"references","in":"query","description":"0 to include only template (renders) consumers","schema":{"type":"string","enum":["0"]}}],"responses":{"200":{"description":"PASS / DEGRADED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"300":{"description":"AMBIGUOUS — name spans products","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"404":{"description":"BLOCKED — no such component","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"503":{"description":"UNAVAILABLE — no renders edges recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}}},"/api/variants/{name}":{"get":{"summary":"Cross-product fork comparison (envelope)","description":"Which products carry a fork of an Angular component, which copies are identical, and where they diverge. Content hashes are computed from product checkouts on the serving host — without checkouts the comparison is UNAVAILABLE (the copy list from the index is still returned).","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"products","in":"query","description":"Comma-separated product filter","schema":{"type":"string","example":"workshop,car,dms"}}],"responses":{"200":{"description":"PASS (complete comparison) / DEGRADED (partial skips)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"404":{"description":"BLOCKED — no angular node matches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"503":{"description":"UNAVAILABLE — no product checkout readable on this host","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}}},"/api/nodes":{"get":{"summary":"List and filter nodes","description":"Return nodes matching filter criteria. Use query params to narrow by type, layer, product, or name substring.","parameters":[{"name":"q","in":"query","description":"Filter by name or node_key substring","schema":{"type":"string"}},{"name":"type","in":"query","description":"Filter by node_type","schema":{"type":"string"}},{"name":"layer","in":"query","description":"Filter by layer","schema":{"type":"string"}},{"name":"product","in":"query","description":"Filter by product","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (default 100)","schema":{"type":"integer","default":100}}],"responses":{"200":{"description":"Array of matching nodes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Node"}}}}}}}},"/api/edges":{"get":{"summary":"List edges (dependencies)","description":"Return edges (relationships between nodes). Optionally filter by edge_type.","parameters":[{"name":"type","in":"query","description":"Filter by edge_type (calls, handles, injects, invokes, executes, reads, writes, queries, etc.)","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (default 500)","schema":{"type":"integer","default":500}}],"responses":{"200":{"description":"Array of edges","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Edge"}}}}}}}},"/api/node/{node_key}":{"get":{"summary":"Get one node and its direct connections (envelope)","description":"Stable exact-key REST lookup backed by the shared node-context application service. The answer contains one node plus inbound and outbound edges, with the same freshness, provenance, and classification semantics as `/api/context/{key}` and the optional MCP adapter. Unlike context, this route never falls back to a name or fuzzy match. Top-level `node`, `inbound`, and `outbound` fields are retained as a deprecated compatibility projection; new clients must read `answer`.","parameters":[{"name":"node_key","in":"path","required":true,"description":"Full product-scoped or database-qualified node_key","schema":{"type":"string"},"example":"proc:GI.dbo.wmQotToPolicy"},{"$ref":"#/components/parameters/AllowStale"},{"$ref":"#/components/parameters/ExpectedRef"},{"$ref":"#/components/parameters/DirectEdgeLimit"}],"responses":{"200":{"description":"PASS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"203":{"description":"DEGRADED — stale provenance or expected-ref mismatch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"404":{"description":"BLOCKED — node not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}}},"/api/products":{"get":{"summary":"List indexed products","description":"Returns all indexed products with node counts broken down by layer and total edge counts.","responses":{"200":{"description":"Products with statistics","content":{"application/json":{"schema":{"type":"object","properties":{"by_layer":{"type":"array","items":{"type":"object","properties":{"product":{"type":"string"},"layer":{"type":"string"},"nodes":{"type":"integer"}}}},"totals":{"type":"array","items":{"type":"object","properties":{"product":{"type":"string"},"total_nodes":{"type":"integer"},"total_edges":{"type":"integer"}}}}}}}}}}}},"/api/graph":{"get":{"summary":"Full graph export","description":"Returns all nodes and edges in the graph, bounded (200k nodes / 400k edges; `truncated` flags a hit). Authenticated like every other graph route. Disable entirely on a server with CODEGRAPH_DISABLE_GRAPH=1. Warning: large response. Use /api/search or /api/blast for targeted queries instead.","parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum nodes returned (hard cap 200000)","schema":{"type":"integer","default":200000,"maximum":200000}}],"responses":{"200":{"description":"Graph data (truncated=true when a cap was reached)","content":{"application/json":{"schema":{"type":"object","properties":{"nodes":{"type":"array","items":{"type":"object","properties":{"node_key":{"type":"string"},"name":{"type":"string"},"node_type":{"type":"string"},"layer":{"type":"string"},"product":{"type":"string"},"file_path":{"type":"string","nullable":true}}}},"edges":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string"},"target":{"type":"string"},"edge_type":{"type":"string"},"confidence":{"type":"number"}}}},"truncated":{"type":"boolean","description":"True when the node or edge cap was reached — this export is not the whole graph."}}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Full graph export disabled on this server (CODEGRAPH_DISABLE_GRAPH=1)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/schema":{"get":{"summary":"OpenAPI specification","description":"Returns this OpenAPI spec. AI agents should call this first to understand all available endpoints.","security":[],"responses":{"200":{"description":"OpenAPI 3.0 specification","content":{"application/json":{"schema":{"type":"object"}}}}}}}}}