Digital Brain API¶
The Digital Brain API provides endpoints for knowledge graph visualization.
Base URL¶
All endpoints are relative to this base URL.
Authentication¶
All endpoints require authentication. Use a service actor token:
Required Scopes:
brain:read- For read endpointsbrain:write- For write endpoints
Perform Action API – Visualization¶
POST /analytics/perform/action
Trigger unified graph rendering. Supports legacy connection_id and preferred connection_ids. If no connections are provided, returns the base knowledge graph schema.
The Fermi app Digital Brain page also calls POST https://api.fermi.dev/core-analytics/visualization/combined/tenant/{tenantId} with { "include_graphiti", "include_manual_kg", "include_saga_nodes" }. That URL works with a service actor token. Partners can keep using /analytics/perform/action below.
Headers:
Request Body:
{
"action": "visualization",
"connection_ids": ["conn_a", "conn_b"],
"discover_external_relationships": true,
"confidence_threshold": "high",
"response_format": "json"
}
Request Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | "visualization" or "views" |
connection_ids | array[string] | No | Multiple connections to merge. Preferred; takes priority over connection_id |
connection_id | string | No | Legacy single-connection input; treated as connection_ids |
discover_external_relationships | boolean | No | Enable LLM-based cross-connection edges (default: true). Forced to false when no connections are provided |
confidence_threshold | string | No | One of "high", "medium", "low" for external relationship filtering (default: "high") |
response_format | string | No | "html" returns PyVis HTML; "json" returns schema-style JSON (default: "html") |
include_saga_nodes | boolean | No | Include saga nodes (default: true) |
query / view_name / message_id / session_id | string | For views | Views action fields |
Behavior:
- With
connection_ids: Uses the base schema, adds each connection's edges, optionally discovers external relationships, returns HTML/JSON based onresponse_format - With
connection_idonly: Treated as single-itemconnection_ids - No connections: Gets the brain directly for the given Organization;
response_format=jsonreturns property-based MongoDB schema JSON, otherwise PyVis HTML
Response Formats:
HTML (response_format=html): - Returns PyVis HTML document of the unified graph
JSON (response_format=json):
Base Schema Path (No Connections):
{
"tenant_id": "...",
"extracted_at": "ISO8601",
"sample_size": 1000,
"node_labels": ["labelA", "..."],
"relationship_types": ["REL_TYPE", "..."],
"node_properties": {
"labelA": {
"prop": {"type": "STRING", "presence_percentage": 100, "sample_values": ["..."]}
}
},
"node_counts": {"labelA": 3},
"relationship_directions": [
{"source_label": "A", "relationship_type": "REL_TYPE", "target_label": "B", "count": 2, "neo4j_type": "REL_TYPE"}
],
"relationship_counts": {"REL_TYPE": 2},
"statistics": {"total_node_labels": 2, "total_relationship_types": 1, "total_nodes": 4, "total_relationships": 2},
"metadata": {
"uses_property_based_types": true,
"relationship_types_from": "edge.name property",
"node_types_from": "node.name property",
"generic_neo4j_labels": ["Entity"],
"extraction_method": "direct_neo4j_query"
}
}
Unified Graph Path (Connections Provided):
{
"tenant_id": "...",
"user_id": "...",
"extracted_at": "ISO8601",
"sample_size": 1000,
"node_labels": ["..."],
"relationship_types": ["..."],
"node_properties": {"Label": {"prop": {"type": "STRING", "presence_percentage": 100, "sample_values": []}}},
"node_counts": {"Label": 4},
"relationship_directions": [
{"source_label": "LabelA", "relationship_type": "REL", "target_label": "LabelB", "count": 1}
],
"relationship_counts": {"REL": 1},
"statistics": {"total_node_labels": 1, "total_relationship_types": 1, "total_nodes": 4, "total_relationships": 1},
"metadata": {
"source": "unified_graph",
"connection_ids": ["conn_a", "conn_b"],
"base_node_count": 10,
"base_edge_count": 5,
"external_relationships_count": 2,
"extraction_method": "unified_graph_conversion"
}
}
Example Requests:
# Base schema HTML
curl --request POST \
--url "${BASE_URL}/analytics/perform/action" \
--header "Authorization: Bearer <token>" \
--header "Content-Type: application/json" \
--data '{"action": "visualization"}'
# Base schema JSON
curl --request POST \
--url "${BASE_URL}/analytics/perform/action" \
--header "Authorization: Bearer <token>" \
--header "Content-Type: application/json" \
--data '{"action": "visualization", "response_format": "json"}'
# Multiple connections JSON
curl --request POST \
--url "${BASE_URL}/analytics/perform/action" \
--header "Authorization: Bearer <token>" \
--header "Content-Type: application/json" \
--data '{
"action": "visualization",
"connection_ids": ["conn_a", "conn_b"],
"response_format": "json"
}'
Error Handling:
- 400 Bad Request: Unknown
action→ 400 with mapping error - 404 Not Found: Data not found scenarios raise 404
- 500 Internal Server Error: Unexpected failures raise 500
Brain Modification & Ontology Updates¶
Apply natural language updates to your Digital Brain. The API parses your text into modification actions (add/replace/invalidate relationships), applies them to your knowledge ontology, and returns a per-action result with a summary.
Endpoint: POST https://api.fermi.dev/public/v1/analytics/chat
This is the Brain update API. Product Ask Fermi uses a different URL — see Chat & Sessions. Sending "action": "graph_modification" without user_input (or query) returns "user_input is required for graph_modification action".
curl -X POST "https://api.fermi.dev/public/v1/analytics/chat" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <service-actor-token>" \
-d '{
"action": "graph_modification",
"user_input": "Replace: Client Amina Patel BELONGS_TO Kisumu Branch instead of Nairobi Branch effective 2024-03-01."
}'
Action: "graph_modification"
Headers:
Request Body:
{
"action": "graph_modification",
"user_input": "Replace: Client Amina Patel BELONGS_TO Kisumu Branch instead of Nairobi Branch effective 2024-03-01.",
"session_id": "default-68d3d439648e3a8ea63411d0",
"category": "Loan Servicing"
}
Request Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Must be "graph_modification" |
user_input | string | Yes (unless query provided) | Natural language feedback text |
query | string | Yes (if user_input omitted) | Alias for user_input |
session_id | string | No | Session identifier for chat history |
category | string | No | Category or domain tag for the modification (e.g. "Loan Servicing") for tagging and categorization |
Response:
The API responds with a graph-modification payload that includes per-action results and a summary.
Response Fields:
| Field | Type | Description |
|---|---|---|
success | string | "true" or "false" |
error | string | "No Errors" or error message |
response | string | "Brain update applied." or "Brain update needs review." |
reason | string | Optional reasoning or failure context |
routing_decision | string | "graph_modification" |
type | string | "graph_modification" |
results | array | Per-action result objects |
summary | object | Counts: { applied, ambiguous, error } |
Result Status Values:
applied: Action applied successfullyambiguous: Multiple or zero matches; needs clarificationerror: Parsing or validation error for that action
Example Success Response:
{
"success": "true",
"error": "No Errors",
"response": "Brain update applied.",
"reason": "",
"routing_decision": "graph_modification",
"type": "graph_modification",
"results": [
{
"status": "applied",
"action": {
"action": "replace",
"source_name": "Client Amina Patel",
"old_relation": "BELONGS_TO",
"old_target_name": "Nairobi Branch",
"new_relation": "BELONGS_TO",
"new_target_name": "Kisumu Branch",
"effective_at": "2024-03-01"
},
"edge_uuid": "8f3d...",
"episode_uuid": "a91b...",
"notes": [],
"affected": {
"invalidated": { "uuid": "8f3d..." },
"added_edges": [],
"added_nodes": []
}
}
],
"summary": { "applied": 1, "ambiguous": 0, "error": 0 }
}
Example Ambiguous Response:
{
"success": "false",
"error": "Brain update not fully applied",
"response": "Brain update needs review.",
"reason": "",
"routing_decision": "graph_modification",
"type": "graph_modification",
"results": [
{
"status": "ambiguous",
"detail": "multiple_matches",
"candidates": [{ "uuid": "..." }, { "uuid": "..." }],
"search_candidates": []
}
],
"summary": { "applied": 0, "ambiguous": 1, "error": 0 }
}
Example Validation Error:
{
"success": "false",
"error": "user_input is required for graph_modification action",
"response": "",
"reason": "Missing user_input",
"routing_decision": "graph_modification",
"type": "graph_modification"
}
cURL Examples:
Add relationships:
curl -X POST "${BASE_URL}/analytics/chat" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <service-actor-token>" \
-d '{
"action": "graph_modification",
"user_input": "Add: Client Amina Patel BELONGS_TO Branch Nairobi. Loan LN-1001 BELONGS_TO Client Amina Patel. Effective 2024-01-01.",
"session_id": "default-68d3d439648e3a8ea63411d0"
}'
Replace a relationship:
curl -X POST "${BASE_URL}/analytics/chat" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <service-actor-token>" \
-d '{
"action": "graph_modification",
"user_input": "Replace: Loan LN-1001 REFERENCES Product Working Capital Loan should be REFERENCES Product Working Capital Loan Plus as of 2024-04-01.",
"session_id": "default-68d3d439648e3a8ea63411d0"
}'
Invalidate/remove a relationship:
curl -X POST "${BASE_URL}/analytics/chat" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <service-actor-token>" \
-d '{
"action": "graph_modification",
"user_input": "Invalidate: Loan LN-1001 REFERENCES Product Working Capital Loan effective 2024-07-01.",
"session_id": "default-68d3d439648e3a8ea63411d0"
}'
Tagging / Categorization¶
You can tag graph modification requests with a category to scope or categorize the update (e.g. by domain such as Loan Servicing). The category parameter is optional on both v1 and v2.
Request body with category:
{
"action": "graph_modification",
"user_input": "Add: Loan LN-1001 REFERENCES Product Working Capital Loan Plus.",
"category": "Loan Servicing"
}
cURL — v1:
curl -X POST "https://api.fermi.dev/public/v1/analytics/chat" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <service-actor-token>" \
-d '{
"action": "graph_modification",
"user_input": "Add: Loan LN-1001 REFERENCES Product Working Capital Loan Plus.",
"category": "Loan Servicing"
}'
cURL — v2:
curl -X POST "https://api.fermi.dev/public/v2/analytics/chat" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <service-actor-token>" \
-d '{
"action": "graph_modification",
"user_input": "Add: Loan LN-1001 REFERENCES Product Working Capital Loan Plus.",
"category": "Loan Servicing"
}'
Sample Queries:
Add: Client Amina Patel BELONGS_TO Branch Nairobi. Loan LN-1001 BELONGS_TO Client Amina Patel. Effective 2024-01-01.Create: Officer John Mwangi WORKS_AT Nairobi Branch and APPROVED Loan LN-1001 on 2024-02-10.Replace: Client Amina Patel BELONGS_TO Kisumu Branch instead of Nairobi Branch effective 2024-03-01.Correction: Loan LN-1001 was not APPROVED_BY John Mwangi; it was APPROVED_BY Mary Wanjiku as of 2024-02-10.Remove: Client Amina Patel WORKS_AT Acme Grocers effective 2024-06-01.Delete the relationship: Officer John Mwangi APPROVED Loan LN-1001 (this never happened).
Tips for Clearer Matches:
- Include both source and target names plus the relationship type
- Add an effective date ("effective", "as of", "on") when relevant
- If results are ambiguous, rephrase with more specific entity names or context
Next Steps¶
- Validation - Review Brain findings after connectors
- API Reference Overview - Return to API reference index
- Chat API - Chat and session management endpoints
- Scopes and Permissions - Learn about required scopes