EIAS API Reference¶
Complete documentation for all EIAS API endpoints.
Base URL¶
Authentication¶
Most endpoints require authentication. The current MVP uses a mock user for development. Production deployments should implement NextAuth.js.
Interview endpoints (/api/interview/*) use token-based access and do not require authentication.
Table of Contents¶
- Health Check
- Dashboard
- Projects
- Uncertainty Areas
- Interview Agents
- Invitations
- Interview (Public)
- Sessions
- Insights
- VOI System
Health Check¶
GET /api/health¶
Check if the API is running.
Response:
Dashboard¶
GET /api/dashboard/stats¶
Get dashboard statistics for the current user.
Response:
Projects¶
GET /api/projects¶
List all projects for the current user.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status: active, paused, completed, archived |
Response:
{
"projects": [
{
"id": "uuid",
"name": "EHR Integration Study",
"description": "Understanding clinical EHR workflows",
"goals": ["Document workflows", "Identify friction points"],
"status": "active",
"createdAt": "2024-01-10T10:00:00.000Z",
"updatedAt": "2024-01-15T14:30:00.000Z",
"_count": {
"uncertaintyAreas": 3,
"agents": 2
}
}
]
}
POST /api/projects¶
Create a new project.
Request Body:
{
"name": "EHR Integration Study",
"description": "Understanding clinical EHR workflows",
"goals": ["Document workflows", "Identify friction points"]
}
Response: 201 Created
{
"id": "uuid",
"name": "EHR Integration Study",
"description": "Understanding clinical EHR workflows",
"goals": ["Document workflows", "Identify friction points"],
"status": "active",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z"
}
GET /api/projects/[id]¶
Get a single project with details.
Response:
{
"id": "uuid",
"name": "EHR Integration Study",
"description": "Understanding clinical EHR workflows",
"goals": ["Document workflows", "Identify friction points"],
"status": "active",
"createdAt": "2024-01-10T10:00:00.000Z",
"updatedAt": "2024-01-15T14:30:00.000Z",
"uncertaintyAreas": [...],
"agents": [...],
"owner": {
"id": "uuid",
"name": "Researcher Name"
}
}
PATCH /api/projects/[id]¶
Update a project.
Request Body:
{
"name": "Updated Name",
"description": "Updated description",
"goals": ["Updated goals"],
"status": "paused"
}
Response: Updated project object
DELETE /api/projects/[id]¶
Delete a project and all related data.
Response: 204 No Content
Uncertainty Areas¶
GET /api/projects/[id]/areas¶
List uncertainty areas for a project.
Response:
{
"areas": [
{
"id": "uuid",
"title": "Documentation Time Burden",
"description": "How much time clinicians spend on documentation",
"priority": "high",
"status": "open",
"questions": [
"What percentage of your day is documentation?",
"Which tasks take the most time?"
],
"createdAt": "2024-01-10T10:00:00.000Z"
}
]
}
POST /api/projects/[id]/areas¶
Create an uncertainty area.
Request Body:
{
"title": "Documentation Time Burden",
"description": "How much time clinicians spend on documentation",
"priority": "high",
"questions": ["What percentage of your day is documentation?"]
}
Response: 201 Created with area object
GET /api/projects/[id]/areas/[areaId]¶
Get a single uncertainty area.
PATCH /api/projects/[id]/areas/[areaId]¶
Update an uncertainty area.
Request Body:
{
"title": "Updated Title",
"description": "Updated description",
"priority": "medium",
"status": "partially_addressed",
"questions": ["Updated questions"]
}
DELETE /api/projects/[id]/areas/[areaId]¶
Delete an uncertainty area.
Response: 204 No Content
Interview Agents¶
GET /api/projects/[id]/agents¶
List interview agents for a project.
Response:
{
"agents": [
{
"id": "uuid",
"name": "Clinical Workflow Interview",
"style": "exploratory",
"timeEstimateMinutes": 20,
"status": "active",
"createdAt": "2024-01-12T10:00:00.000Z",
"focusAreas": [
{
"uncertaintyArea": {
"id": "uuid",
"title": "Documentation Time Burden"
}
}
],
"_count": {
"invitations": 3
}
}
]
}
POST /api/projects/[id]/agents¶
Create an interview agent.
Request Body:
{
"name": "Clinical Workflow Interview",
"focusAreaIds": ["area-uuid-1", "area-uuid-2"],
"style": "exploratory",
"timeEstimateMinutes": 20
}
The system automatically generates a systemPrompt based on the project context and selected focus areas.
Response: 201 Created with agent object including generated system prompt
POST /api/projects/[id]/agents/generate-prompt¶
Preview the system prompt that would be generated for an agent configuration.
Request Body:
{
"name": "Test Agent",
"focusAreaIds": ["area-uuid-1"],
"style": "focused",
"timeEstimateMinutes": 15
}
Response:
GET /api/projects/[id]/agents/[agentId]¶
Get a single agent with details.
PATCH /api/projects/[id]/agents/[agentId]¶
Update an agent.
Request Body:
{
"name": "Updated Name",
"status": "paused",
"focusAreaIds": ["area-uuid-1"],
"style": "validating",
"timeEstimateMinutes": 30
}
DELETE /api/projects/[id]/agents/[agentId]¶
Delete an agent.
Response: 204 No Content
Invitations¶
GET /api/projects/[id]/agents/[agentId]/invitations¶
List invitations for an agent.
Response:
{
"invitations": [
{
"id": "uuid",
"expertName": "Dr. Jane Smith",
"expertRole": "Physician",
"expertEmail": "jane@example.com",
"token": "secure-token-string",
"expiresAt": "2024-01-22T10:00:00.000Z",
"status": "pending",
"createdAt": "2024-01-15T10:00:00.000Z",
"session": null
}
]
}
POST /api/projects/[id]/agents/[agentId]/invitations¶
Create an invitation.
Request Body:
{
"expertName": "Dr. Jane Smith",
"expertRole": "Physician",
"expertEmail": "jane@example.com",
"expiresInDays": 7
}
Response: 201 Created
{
"id": "uuid",
"expertName": "Dr. Jane Smith",
"expertRole": "Physician",
"token": "secure-token-string",
"expiresAt": "2024-01-22T10:00:00.000Z",
"status": "pending",
"interviewUrl": "http://localhost:3000/interview/secure-token-string"
}
GET /api/projects/[id]/agents/[agentId]/invitations/[invitationId]¶
Get a single invitation.
PATCH /api/projects/[id]/agents/[agentId]/invitations/[invitationId]¶
Update an invitation (e.g., extend expiration).
Request Body:
DELETE /api/projects/[id]/agents/[agentId]/invitations/[invitationId]¶
Delete an invitation.
Response: 204 No Content
Interview (Public)¶
These endpoints are accessed by experts via their invitation token. No authentication required.
GET /api/interview/[token]¶
Validate token and get interview context.
Response (valid token):
{
"valid": true,
"invitation": {
"expertName": "Dr. Jane Smith",
"expertRole": "Physician",
"status": "pending"
},
"agent": {
"name": "Clinical Workflow Interview",
"timeEstimateMinutes": 20
},
"project": {
"name": "EHR Integration Study",
"description": "Understanding clinical EHR workflows"
},
"session": null
}
Response (invalid/expired token):
POST /api/interview/[token]/start¶
Start a new interview session.
Request Body: None required
Response: 201 Created
{
"sessionId": "uuid",
"welcomeMessage": "Hello Dr. Smith! I'm here to learn about your experience with clinical workflows..."
}
POST /api/interview/[token]/chat¶
Send a message and get agent response.
Request Body:
Response:
{
"response": "That's a significant amount of time. Could you tell me which specific documentation tasks consume the most of those 3 hours?",
"sessionId": "uuid",
"turnCount": 4
}
POST /api/interview/[token]/complete¶
Complete the interview session.
Request Body:
{
"corrections": "One clarification: I mentioned 3 hours but that includes both clinical notes and administrative paperwork.",
"rating": 5
}
Response:
Sessions¶
GET /api/projects/[id]/agents/[agentId]/sessions¶
List sessions for an agent.
Response:
{
"sessions": [
{
"id": "uuid",
"status": "completed",
"startedAt": "2024-01-15T14:00:00.000Z",
"completedAt": "2024-01-15T14:25:00.000Z",
"turnCount": 12,
"expertRating": 5,
"invitation": {
"expertName": "Dr. Jane Smith",
"expertRole": "Physician"
},
"_count": {
"insights": 5
}
}
]
}
GET /api/projects/[id]/agents/[agentId]/sessions/[sessionId]¶
Get a session with full transcript.
Response:
{
"id": "uuid",
"status": "completed",
"startedAt": "2024-01-15T14:00:00.000Z",
"completedAt": "2024-01-15T14:25:00.000Z",
"turnCount": 12,
"expertCorrections": "Clarification about documentation time",
"expertRating": 5,
"invitation": {
"expertName": "Dr. Jane Smith",
"expertRole": "Physician"
},
"messages": [
{
"id": "uuid",
"role": "assistant",
"content": "Hello Dr. Smith! I'm here to learn about...",
"timestamp": "2024-01-15T14:00:00.000Z"
},
{
"id": "uuid",
"role": "user",
"content": "I typically spend about 3 hours...",
"timestamp": "2024-01-15T14:01:30.000Z"
}
],
"insights": [...]
}
Insights¶
POST /api/projects/[id]/agents/[agentId]/sessions/[sessionId]/insights¶
Extract insights from a completed session.
Request Body: None required
Response: 201 Created
{
"insights": [
{
"id": "uuid",
"content": "Clinicians spend approximately 3 hours daily on documentation tasks",
"category": "factual_claim",
"confidence": "high",
"status": "pending_review",
"sourceMessages": [
{
"messageId": "uuid",
"message": {
"content": "I typically spend about 3 hours on documentation per day."
}
}
]
}
],
"count": 5
}
GET /api/projects/[id]/agents/[agentId]/sessions/[sessionId]/insights¶
List insights for a session.
Response:
{
"insights": [
{
"id": "uuid",
"content": "Clinicians spend approximately 3 hours daily on documentation tasks",
"category": "factual_claim",
"confidence": "high",
"status": "pending_review",
"reviewerNotes": null,
"createdAt": "2024-01-15T15:00:00.000Z",
"sourceMessages": [...]
}
]
}
PATCH /api/projects/[id]/agents/[agentId]/sessions/[sessionId]/insights/[insightId]¶
Update an insight (review action).
Request Body:
Status options:
- pending_review — Default, awaiting review
- integrated — Approved and added to project knowledge
- discarded — Rejected, not useful
- review_later — Deferred for later review
Response: Updated insight object
GET /api/projects/[id]/insights¶
Get all insights for a project (aggregated view).
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status |
category |
string | Filter by category |
confidence |
string | Filter by confidence |
Response:
{
"insights": [...],
"stats": {
"total": 25,
"pending": 10,
"integrated": 12,
"discarded": 3,
"highConfidence": 15
}
}
Error Responses¶
All endpoints return consistent error responses:
Common Error Codes¶
| Code | HTTP Status | Description |
|---|---|---|
NOT_FOUND |
404 | Resource does not exist |
UNAUTHORIZED |
401 | Authentication required |
FORBIDDEN |
403 | Insufficient permissions |
VALIDATION_ERROR |
400 | Invalid request body |
TOKEN_EXPIRED |
400 | Invitation token has expired |
TOKEN_INVALID |
400 | Invitation token is invalid |
SESSION_ALREADY_EXISTS |
400 | Interview already started |
SESSION_COMPLETED |
400 | Cannot modify completed session |
RATE_LIMITED |
429 | Too many requests |
INTERNAL_ERROR |
500 | Server error |
Rate Limiting¶
| Endpoint | Limit |
|---|---|
/api/interview/[token]/chat |
20 requests/minute per session |
| All other endpoints | 100 requests/minute per user |
Rate limit headers:
Webhooks (Future)¶
Webhooks for integration with external systems are planned for a future release:
interview.completed— When an expert completes an interviewinsights.extracted— When insights are extracted from a sessioninsight.integrated— When an insight is integrated
SDK Examples¶
JavaScript/TypeScript¶
// Fetch projects
const response = await fetch('/api/projects');
const { projects } = await response.json();
// Create invitation
const inviteResponse = await fetch(`/api/projects/${projectId}/agents/${agentId}/invitations`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
expertName: 'Dr. Jane Smith',
expertRole: 'Physician',
expiresInDays: 7
})
});
const invitation = await inviteResponse.json();
console.log('Interview URL:', invitation.interviewUrl);
Python¶
import requests
# Fetch projects
response = requests.get('http://localhost:3000/api/projects')
projects = response.json()['projects']
# Create invitation
invite_response = requests.post(
f'http://localhost:3000/api/projects/{project_id}/agents/{agent_id}/invitations',
json={
'expertName': 'Dr. Jane Smith',
'expertRole': 'Physician',
'expiresInDays': 7
}
)
invitation = invite_response.json()
print(f"Interview URL: {invitation['interviewUrl']}")
VOI System¶
The VOI (Value of Information) system provides intelligent interview orchestration through research decomposition, adaptive questioning, and cross-interview synthesis.
Research Decomposition¶
POST /api/projects/[id]/decompose¶
Decompose a research question into sub-questions with dependency tracking.
Request Body:
{
"researchQuestion": "How do clinicians experience EHR documentation burden?",
"maxSubQuestions": 8,
"expertDomains": ["clinical informatics", "health IT"]
}
Response: 201 Created
{
"subQuestions": [
{
"id": "uuid",
"title": "Time allocation for documentation",
"description": "How much time do clinicians spend on documentation vs patient care?",
"priority": "high",
"status": "uncovered",
"confidence": 0,
"dependencies": []
},
{
"id": "uuid",
"title": "Documentation workflow pain points",
"description": "What specific steps in the documentation process cause the most friction?",
"priority": "high",
"status": "uncovered",
"confidence": 0,
"dependencies": ["uuid-of-time-allocation"]
}
],
"decompositionId": "uuid",
"metadata": {
"totalSubQuestions": 6,
"highPriority": 3,
"mediumPriority": 2,
"lowPriority": 1
}
}
Sub-Questions¶
GET /api/projects/[id]/subquestions/[subquestionId]¶
Get a sub-question with its findings and status.
Response:
{
"id": "uuid",
"title": "Time allocation for documentation",
"description": "How much time do clinicians spend on documentation vs patient care?",
"priority": "high",
"status": "partial",
"confidence": 0.65,
"currentAnswer": "Clinicians report spending 2-4 hours daily on documentation...",
"dependencies": [],
"findings": [
{
"id": "uuid",
"summary": "Physicians spend average 3 hours/day on documentation",
"confidence": "high",
"expertId": "uuid",
"turnNumber": 4
}
],
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-16T14:30:00.000Z"
}
PATCH /api/projects/[id]/subquestions/[subquestionId]¶
Update a sub-question (refine, change priority, or manually update status).
Request Body:
{
"title": "Updated title",
"description": "Refined description",
"priority": "medium",
"status": "answered",
"confidence": 0.85
}
Response: Updated sub-question object
VOI Calculation¶
POST /api/projects/[id]/voi¶
Calculate Value of Information for candidate questions.
Request Body:
{
"expertId": "uuid",
"sessionId": "uuid",
"candidateQuestions": [
"What percentage of your workday involves documentation?",
"Which EHR features do you find most time-consuming?",
"How does documentation affect your patient interactions?"
]
}
Response:
{
"rankings": [
{
"question": "Which EHR features do you find most time-consuming?",
"voi": 0.42,
"expectedUtilityGain": 0.15,
"targetSubQuestions": ["uuid-1", "uuid-2"],
"rationale": "High coverage potential for uncovered sub-questions"
},
{
"question": "What percentage of your workday involves documentation?",
"voi": 0.38,
"expectedUtilityGain": 0.12,
"targetSubQuestions": ["uuid-1"],
"rationale": "Directly addresses high-priority sub-question"
},
{
"question": "How does documentation affect your patient interactions?",
"voi": 0.25,
"expectedUtilityGain": 0.08,
"targetSubQuestions": ["uuid-3"],
"rationale": "Exploratory question with moderate coverage"
}
],
"currentUtility": {
"coverage": 0.45,
"confidence": 0.52,
"coherence": 0.78,
"actionability": 0.35,
"total": 0.51
},
"recommendedQuestion": "Which EHR features do you find most time-consuming?"
}
Adaptive Interviews¶
POST /api/interviews¶
Start a new adaptive interview session with VOI-driven question selection.
Request Body:
Response: 201 Created
{
"sessionId": "uuid",
"welcomeMessage": "Hello Dr. Smith! I'm conducting research on clinical documentation...",
"phase": "greeting",
"knowledgeState": {
"subQuestionsCovered": 0,
"totalSubQuestions": 6,
"coverage": 0
}
}
GET /api/interviews¶
List interview sessions with optional filtering.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
projectId |
string | Filter by project |
status |
string | Filter by status: active, completed, abandoned, paused |
limit |
number | Results per page (default: 20) |
offset |
number | Pagination offset |
Response:
{
"sessions": [
{
"id": "uuid",
"status": "active",
"phase": "interviewing",
"turnNumber": 5,
"startedAt": "2024-01-15T14:00:00.000Z",
"invitation": {
"expertName": "Dr. Jane Smith",
"expertRole": "Physician"
},
"analytics": {
"findingsCount": 3,
"subQuestionsAddressed": 2,
"totalSubQuestions": 6,
"utilityScore": 0.58
}
}
],
"total": 15,
"limit": 20,
"offset": 0
}
GET /api/interviews/[sessionId]¶
Get detailed interview state including knowledge progress.
Response:
{
"id": "uuid",
"status": "active",
"phase": "interviewing",
"turnNumber": 8,
"startedAt": "2024-01-15T14:00:00.000Z",
"invitation": {
"expertName": "Dr. Jane Smith",
"expertRole": "Physician"
},
"messages": [
{
"role": "assistant",
"content": "Hello Dr. Smith!...",
"timestamp": "2024-01-15T14:00:00.000Z"
}
],
"knowledgeState": {
"subQuestions": [
{
"id": "uuid",
"title": "Time allocation",
"status": "partial",
"confidence": 0.65
}
],
"findings": [
{
"id": "uuid",
"summary": "3 hours/day on documentation",
"confidence": "high",
"turnNumber": 4
}
],
"contradictions": []
},
"analytics": {
"turnCount": 8,
"findingsCount": 4,
"subQuestionsAddressed": 3,
"totalSubQuestions": 6,
"utilityScore": 0.62,
"phase": "interviewing"
}
}
POST /api/interviews/[sessionId]¶
Continue an interview with expert response.
Request Body:
{
"message": "I typically spend about 3 hours on documentation each day, mostly on progress notes and medication reconciliation."
}
Response:
{
"response": "That's helpful context. You mentioned medication reconciliation specifically - could you walk me through that process?",
"turnNumber": 9,
"phase": "interviewing",
"voiAnalysis": {
"selectedQuestion": "medication reconciliation process",
"voi": 0.38,
"rationale": "Follow-up addresses partially covered sub-question"
},
"findingsExtracted": [
{
"id": "uuid",
"summary": "3 hours daily on documentation, primarily progress notes and med rec",
"confidence": "high",
"subQuestionIds": ["uuid-1", "uuid-2"]
}
]
}
DELETE /api/interviews/[sessionId]¶
Abort an interview session.
Response:
Synthesis¶
POST /api/projects/[id]/synthesis¶
Generate a synthesis report across all completed interviews.
Request Body:
Response:
{
"projectId": "uuid",
"generatedAt": "2024-01-20T10:00:00.000Z",
"subQuestionSummaries": [
{
"subQuestionId": "uuid",
"title": "Time allocation for documentation",
"status": "answered",
"confidence": 0.85,
"synthesizedAnswer": "Clinicians consistently report spending 2-4 hours daily on documentation, with progress notes and medication reconciliation consuming the majority of time.",
"supportingFindings": [
{
"findingId": "uuid",
"summary": "3 hours/day on documentation",
"expertWeight": 0.35,
"confidence": "high"
}
],
"expertCount": 4
}
],
"contradictions": [
{
"id": "uuid",
"description": "Conflicting reports on documentation time",
"nature": "quantitative_disagreement",
"status": "unresolved",
"findingA": {
"id": "uuid",
"summary": "2 hours/day",
"expertId": "uuid"
},
"findingB": {
"id": "uuid",
"summary": "5 hours/day",
"expertId": "uuid"
}
}
],
"overallProgress": {
"subQuestionsCovered": 5,
"totalSubQuestions": 6,
"coverage": 0.83,
"averageConfidence": 0.72
},
"executiveSummary": "Based on 4 expert interviews, this synthesis reveals..."
}
GET /api/projects/[id]/synthesis/stats¶
Get synthesis statistics for a project.
Response:
{
"totalInterviews": 6,
"completedInterviews": 4,
"totalFindings": 28,
"subQuestionsCovered": 5,
"subQuestionsTotal": 6,
"unresolvedContradictions": 2,
"totalContradictions": 3,
"overallCoverage": 0.83
}
GET /api/projects/[id]/contradictions¶
List contradictions for a project.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status: unresolved, resolved, acknowledged |
Response:
{
"contradictions": [
{
"id": "uuid",
"description": "Conflicting reports on documentation time",
"nature": "quantitative_disagreement",
"status": "unresolved",
"resolution": null,
"findingA": {
"id": "uuid",
"summary": "2 hours/day",
"expertId": "uuid"
},
"findingB": {
"id": "uuid",
"summary": "5 hours/day",
"expertId": "uuid"
}
}
]
}
POST /api/projects/[id]/contradictions/[contradictionId]/resolve¶
Resolve a contradiction.
Request Body:
{
"resolution": "The discrepancy likely reflects different clinical settings - the 2-hour estimate came from an outpatient physician while the 5-hour estimate came from an inpatient hospitalist.",
"status": "resolved"
}
Response:
{
"id": "uuid",
"status": "resolved",
"resolution": "The discrepancy likely reflects different clinical settings...",
"resolvedAt": "2024-01-20T15:30:00.000Z"
}
Related Documentation¶
- Getting Started — Setup and installation
- User Guide — How to use EIAS
- Deployment — Production hosting