Skip to content

Insights API

The Insights API provides endpoints for AI-powered workbook analysis, insight generation, and natural language Q&A.


Overview

CalcBridge's insights engine supports:

  • Workbook Nomination: Select workbooks for AI analysis
  • Insight Generation: AI-powered pattern detection and anomaly analysis
  • Stakeholder Views: Insights tailored for executives, finance, operations, or analysts
  • Natural Language Q&A: Ask questions about your data in plain English

Endpoints

Get Nominations

Get all workbooks with their nomination status.

GET /api/v1/insights/nominations

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/insights/nominations" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    "https://api.calcbridge.io/api/v1/insights/nominations",
    headers={"Authorization": f"Bearer {token}"}
)
nominations = response.json()
for wb in nominations:
    status = "nominated" if wb["is_nominated"] else "not nominated"
    print(f"{wb['workbook_name']}: {status}")
const response = await fetch(
  'https://api.calcbridge.io/api/v1/insights/nominations',
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const nominations = await response.json();
nominations.forEach(wb => {
  console.log(`${wb.workbook_name}: ${wb.is_nominated ? 'nominated' : 'not nominated'}`);
});

Response

[
  {
    "workbook_id": "550e8400-e29b-41d4-a716-446655440000",
    "workbook_name": "CLO Portfolio Q1 2026",
    "is_nominated": true,
    "nominated_at": "2026-01-25T10:00:00Z"
  },
  {
    "workbook_id": "550e8400-e29b-41d4-a716-446655440001",
    "workbook_name": "Holdings Report",
    "is_nominated": false,
    "nominated_at": null
  }
]

Update Nomination

Toggle nomination status for a workbook.

PUT /api/v1/insights/nominations/{workbook_id}

Path Parameters

Parameter Type Description
workbook_id string (UUID) Workbook identifier

Request Body

Field Type Required Description
is_nominated boolean Yes Whether to nominate the workbook for analysis

Example Request

curl -X PUT "https://api.calcbridge.io/api/v1/insights/nominations/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"is_nominated": true}'
import requests

response = requests.put(
    f"https://api.calcbridge.io/api/v1/insights/nominations/{workbook_id}",
    headers={"Authorization": f"Bearer {token}"},
    json={"is_nominated": True}
)
result = response.json()
print(f"Nomination updated: {result['is_nominated']}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/insights/nominations/${workbookId}`,
  {
    method: 'PUT',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ is_nominated: true })
  }
);
const result = await response.json();
console.log('Nomination updated:', result.is_nominated);

Response

{
  "workbook_id": "550e8400-e29b-41d4-a716-446655440000",
  "workbook_name": "CLO Portfolio Q1 2026",
  "is_nominated": true,
  "nominated_at": "2026-01-25T10:00:00Z"
}

Error Responses

Status Error Description
404 Workbook not found Invalid workbook_id or access denied

Bulk Update Nominations

Bulk update nomination status for multiple workbooks.

POST /api/v1/insights/nominations/bulk

Request Body

Field Type Required Description
workbook_ids string[] Yes Workbook IDs to update
is_nominated boolean Yes Nomination status to apply

Example Request

curl -X POST https://api.calcbridge.io/api/v1/insights/nominations/bulk \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workbook_ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "550e8400-e29b-41d4-a716-446655440001"
    ],
    "is_nominated": true
  }'
import requests

response = requests.post(
    "https://api.calcbridge.io/api/v1/insights/nominations/bulk",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "workbook_ids": [
            "550e8400-e29b-41d4-a716-446655440000",
            "550e8400-e29b-41d4-a716-446655440001"
        ],
        "is_nominated": True
    }
)
result = response.json()
print(f"Updated {result['updated_count']} workbooks")
const response = await fetch('https://api.calcbridge.io/api/v1/insights/nominations/bulk', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    workbook_ids: [
      '550e8400-e29b-41d4-a716-446655440000',
      '550e8400-e29b-41d4-a716-446655440001'
    ],
    is_nominated: true
  })
});
const result = await response.json();
console.log('Updated:', result.updated_count, 'workbooks');

Response

{
  "updated_count": 2,
  "workbook_ids": [
    "550e8400-e29b-41d4-a716-446655440000",
    "550e8400-e29b-41d4-a716-446655440001"
  ],
  "is_nominated": true
}

Generate Insights

Generate AI-powered insights from nominated workbooks.

POST /api/v1/insights/generate

Request Body

Field Type Default Description
stakeholder_type string analyst View: executive, finance, operations, analyst

Example Request

curl -X POST https://api.calcbridge.io/api/v1/insights/generate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"stakeholder_type": "executive"}'
import requests

response = requests.post(
    "https://api.calcbridge.io/api/v1/insights/generate",
    headers={"Authorization": f"Bearer {token}"},
    json={"stakeholder_type": "executive"}
)
session = response.json()
print(f"Session: {session['session_id']}")
for insight in session["insights"]:
    print(f"  [{insight['category']}] {insight['title']} (confidence: {insight['confidence']})")
const response = await fetch('https://api.calcbridge.io/api/v1/insights/generate', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ stakeholder_type: 'executive' })
});
const session = await response.json();
console.log('Session:', session.session_id);
session.insights.forEach(insight => {
  console.log(`[${insight.category}] ${insight.title}`);
});

Response

{
  "session_id": "sess_abc123",
  "status": "completed",
  "regeneration_count": 0,
  "insights": [
    {
      "id": "ins_001",
      "category": "financial_health",
      "category_display": "Financial Health",
      "title": "Portfolio concentration risk increasing",
      "summary": "Top 5 obligors now represent 32% of total par, up from 28% last quarter.",
      "confidence": 0.92,
      "priority": 1,
      "is_taster": false
    },
    {
      "id": "ins_002",
      "category": "risk_compliance",
      "category_display": "Risk & Compliance",
      "title": "CCC bucket approaching covenant threshold",
      "summary": "CCC rated assets at 6.8% of portfolio, within 0.7% of the 7.5% limit.",
      "confidence": 0.95,
      "priority": 2,
      "is_taster": false
    },
    {
      "id": "ins_003",
      "category": "trends_forecasts",
      "category_display": "Trends & Forecasts",
      "title": "Weighted average spread compression trend",
      "summary": "WAS has declined 15bps over the past 3 months, potentially impacting IC test cushion.",
      "confidence": 0.87,
      "priority": 3,
      "is_taster": false
    }
  ],
  "created_at": "2026-01-25T10:30:00Z"
}

Error Responses

Status Error Description
400 No nominated workbooks No workbooks have been nominated for analysis
400 Invalid stakeholder type Unknown stakeholder_type value
429 Rate limit exceeded Insight generation quota exceeded

Regenerate Insights

Regenerate insights for the current session. Maximum 3 regenerations per session.

POST /api/v1/insights/regenerate

Example Request

curl -X POST "https://api.calcbridge.io/api/v1/insights/regenerate" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.post(
    "https://api.calcbridge.io/api/v1/insights/regenerate",
    headers={"Authorization": f"Bearer {token}"}
)
session = response.json()
print(f"Regeneration #{session['regeneration_count']}")
print(f"New insights: {len(session['insights'])}")
const response = await fetch('https://api.calcbridge.io/api/v1/insights/regenerate', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${token}` }
});
const session = await response.json();
console.log('Regeneration #' + session.regeneration_count);

Response

Returns the same session object as Generate Insights with updated insights and incremented regeneration_count.

Error Responses

Status Error Description
400 No active session No insight session exists to regenerate
429 Regeneration limit reached Maximum 3 regenerations per session

Get Current Session

Get the current active insight session with all insights.

GET /api/v1/insights/sessions/current

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/insights/sessions/current" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    "https://api.calcbridge.io/api/v1/insights/sessions/current",
    headers={"Authorization": f"Bearer {token}"}
)
session = response.json()
print(f"Session: {session['session_id']}")
print(f"Insights: {len(session['insights'])}")
const response = await fetch(
  'https://api.calcbridge.io/api/v1/insights/sessions/current',
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const session = await response.json();
console.log('Session:', session.session_id);

Response

Returns the full session object with all insights.

Error Responses

Status Error Description
404 No active session No insight session exists for the current user

Get Session

Get a specific insight session by ID.

GET /api/v1/insights/sessions/{session_id}

Path Parameters

Parameter Type Description
session_id string Insight session identifier

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/insights/sessions/sess_abc123" \
  -H "Authorization: Bearer $TOKEN"

Response

Returns the full session object with all insights.

Error Responses

Status Error Description
404 Session not found Invalid session_id or access denied

Get Insight Detail

Get detailed information about a specific insight, including methodology and supporting data.

GET /api/v1/insights/{insight_id}

Path Parameters

Parameter Type Description
insight_id string Insight identifier

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/insights/ins_001" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    f"https://api.calcbridge.io/api/v1/insights/{insight_id}",
    headers={"Authorization": f"Bearer {token}"}
)
insight = response.json()
print(f"Title: {insight['title']}")
print(f"Methodology: {insight['methodology']}")
print(f"Supporting Data: {insight['supporting_data']}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/insights/${insightId}`,
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const insight = await response.json();
console.log('Title:', insight.title);
console.log('Methodology:', insight.methodology);

Response

{
  "id": "ins_001",
  "category": "financial_health",
  "category_display": "Financial Health",
  "title": "Portfolio concentration risk increasing",
  "summary": "Top 5 obligors now represent 32% of total par, up from 28% last quarter.",
  "confidence": 0.92,
  "priority": 1,
  "is_taster": false,
  "methodology": "Statistical analysis of obligor exposure trends over trailing 4 quarters using Herfindahl-Hirschman Index (HHI) decomposition.",
  "supporting_data": {
    "top_5_exposure_current": 0.32,
    "top_5_exposure_previous": 0.28,
    "top_5_exposure_2q_ago": 0.26,
    "threshold": 0.35,
    "hhi_current": 0.045,
    "hhi_previous": 0.038
  },
  "created_at": "2026-01-25T10:30:00Z",
  "recent_questions": []
}

Error Responses

Status Error Description
404 Insight not found Invalid insight_id or access denied

Ask Insight Question

Ask a follow-up question about a specific insight.

POST /api/v1/insights/{insight_id}/ask

Path Parameters

Parameter Type Description
insight_id string Insight identifier

Request Body

Field Type Required Description
question string Yes Question text (1-1000 characters)

Example Request

curl -X POST "https://api.calcbridge.io/api/v1/insights/ins_001/ask" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"question": "Which obligors are driving the concentration increase?"}'
import requests

response = requests.post(
    f"https://api.calcbridge.io/api/v1/insights/{insight_id}/ask",
    headers={"Authorization": f"Bearer {token}"},
    json={"question": "Which obligors are driving the concentration increase?"}
)
qa = response.json()
print(f"Q: {qa['question']}")
print(f"A: {qa['answer']}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/insights/${insightId}/ask`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      question: 'Which obligors are driving the concentration increase?'
    })
  }
);
const qa = await response.json();
console.log('Answer:', qa.answer);

Response

{
  "question": "Which obligors are driving the concentration increase?",
  "answer": "The concentration increase is primarily driven by three obligors: Acme Corp (increased from 7.2% to 8.5%), Tech Industries (6.1% to 7.3%), and Global Services (5.8% to 6.4%). The combined increase of 3.1 percentage points accounts for the majority of the shift from 28% to 32%.",
  "insight_id": "ins_001",
  "asked_at": "2026-01-25T11:00:00Z"
}

Error Responses

Status Error Description
400 Invalid question Question is empty or exceeds 1000 characters
404 Insight not found Invalid insight_id or access denied
429 Rate limit exceeded Question quota exceeded

Ask Global Question

Ask a general question about your workbook data without referencing a specific insight.

POST /api/v1/insights/ask

Request Body

Field Type Required Description
question string Yes Question text (1-1000 characters)

Example Request

curl -X POST "https://api.calcbridge.io/api/v1/insights/ask" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"question": "What is my current OC test cushion?"}'
import requests

response = requests.post(
    "https://api.calcbridge.io/api/v1/insights/ask",
    headers={"Authorization": f"Bearer {token}"},
    json={"question": "What is my current OC test cushion?"}
)
qa = response.json()
print(f"A: {qa['answer']}")
const response = await fetch('https://api.calcbridge.io/api/v1/insights/ask', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    question: 'What is my current OC test cushion?'
  })
});
const qa = await response.json();
console.log('Answer:', qa.answer);

Response

{
  "question": "What is my current OC test cushion?",
  "answer": "Your Senior OC test currently has a cushion of 3.2% above the trigger level of 120.0%, with a current ratio of 123.2%. The Subordinate OC test has a cushion of 1.8% above its 108.0% trigger, at 109.8%.",
  "insight_id": null,
  "asked_at": "2026-01-25T11:05:00Z"
}

Get Question History

Get the user's Q&A history across all insights.

GET /api/v1/insights/questions/history

Query Parameters

Parameter Type Default Description
limit integer 20 Maximum results to return (max 100)

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/insights/questions/history?limit=10" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    "https://api.calcbridge.io/api/v1/insights/questions/history",
    headers={"Authorization": f"Bearer {token}"},
    params={"limit": 10}
)
history = response.json()
for qa in history:
    print(f"Q: {qa['question']}")
    print(f"A: {qa['answer'][:100]}...")
    print()
const response = await fetch(
  'https://api.calcbridge.io/api/v1/insights/questions/history?limit=10',
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const history = await response.json();
history.forEach(qa => {
  console.log(`Q: ${qa.question}`);
  console.log(`A: ${qa.answer.substring(0, 100)}...`);
});

Response

[
  {
    "question": "Which obligors are driving the concentration increase?",
    "answer": "The concentration increase is primarily driven by three obligors...",
    "insight_id": "ins_001",
    "asked_at": "2026-01-25T11:00:00Z"
  },
  {
    "question": "What is my current OC test cushion?",
    "answer": "Your Senior OC test currently has a cushion of 3.2%...",
    "insight_id": null,
    "asked_at": "2026-01-25T11:05:00Z"
  }
]

Insight Categories

Category Key Description
Financial Health financial_health Portfolio-level financial metrics and trends
Operational Efficiency operational_efficiency Process and workflow optimization opportunities
Risk & Compliance risk_compliance Risk exposures and compliance concerns
Trends & Forecasts trends_forecasts Data patterns and forward-looking analysis
Recommendations recommendations Actionable improvement suggestions

Stakeholder Views

Type Focus
executive High-level KPIs, strategic trends, board-level metrics
finance Detailed financial metrics, variances, accounting insights
operations Efficiency metrics, resource allocation, operational performance
analyst Data patterns, statistical insights, detailed analysis

Best Practices

  1. Nominate relevant workbooks: Only nominate workbooks with current, complete data
  2. Choose the right stakeholder view: Select the view matching your audience
  3. Use follow-up questions: Drill into insights with targeted questions
  4. Review confidence scores: Prioritize high-confidence insights for decision-making
  5. Regenerate sparingly: Use regeneration when insights miss key areas
  6. Check question history: Avoid duplicate questions by reviewing history