Skip to content

Digital Brain API

The Digital Brain API provides endpoints for knowledge graph visualization.

Base URL

BASE_URL = "https://api.fermi.dev/public/v1"

All endpoints are relative to this base URL.

Authentication

All endpoints require authentication. Use a service actor token:

Authorization: Bearer <service-actor-token>

Required Scopes:

  • brain:read - For read endpoints
  • brain: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:

Authorization: Bearer <token>
Content-Type: application/json

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 on response_format
  • With connection_id only: Treated as single-item connection_ids
  • No connections: Gets the brain directly for the given Organization; response_format=json returns 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:

Authorization: Bearer <token>
Content-Type: application/json

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 successfully
  • ambiguous: Multiple or zero matches; needs clarification
  • error: 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