API Reference

Complete API endpoints, server actions, and integration guide

API Reference

This document provides comprehensive documentation for all API endpoints and Server Actions available in SehatScan.


Table of Contents

  1. Authentication
  2. Server Actions
  3. REST API Endpoints
  4. Error Handling
  5. Rate Limiting

Authentication

All API endpoints and Server Actions require authentication unless otherwise specified. Authentication is handled via Clerk.

Authentication Header

For REST API calls, include the Clerk session token:

Authorization: Bearer <clerk_session_token>

Server-Side Authentication

Server Actions automatically access the Clerk session:

import { getCurrentUser, requireAuth } from '@/lib/clerk-session'

// Get current user (returns null if not authenticated)
const user = await getCurrentUser()

// Require authentication (throws error if not authenticated)
const user = await requireAuth()

Server Actions

Server Actions are the primary method for data mutations. They are located in /app/actions/.

Scan Actions (/app/actions/scan.ts)

analyzeReport(formData: FormData)

Analyzes a medical report document using AI.

Parameters:

FieldTypeRequiredDescription
fileFileYesThe medical report file (PDF, JPG, PNG)

Returns:

interface AnalyzeReportResult {
  success: boolean
  data?: {
    id: string
    raw_text: string
    structured_data: {
      metrics: Array<{
        name: string
        value: string
        unit: string
        status: 'normal' | 'low' | 'high' | 'critical'
        reference_range?: string
      }>
      problems_detected: Array<{
        name: string
        severity: 'low' | 'moderate' | 'high' | 'critical'
        description: string
      }>
      treatments: Array<{
        recommendation: string
        priority: 'low' | 'medium' | 'high'
      }>
      summary: string
    }
  }
  error?: string
}

Usage:

import { analyzeReport } from '@/app/actions/scan'

const formData = new FormData()
formData.append('file', selectedFile)

const result = await analyzeReport(formData)

if (result.success) {
  console.log('Analysis:', result.data)
} else {
  console.error('Error:', result.error)
}

analyzeFace(formData: FormData)

Analyzes a face photo for health indicators.

Parameters:

FieldTypeRequiredDescription
fileFileYesFace photo (JPG, PNG only)

Returns:

interface AnalyzeFaceResult {
  success: boolean
  data?: {
    id: string
    face_detected: boolean
    face_count: number
    visual_metrics: {
      redness_percentage: number
      yellowness_percentage: number
      skin_tone: string
    }
    problems_detected: Array<{
      type: string
      severity: 'low' | 'moderate' | 'high'
      description: string
      confidence: number
    }>
    treatments: Array<{
      recommendation: string
      priority: 'low' | 'medium' | 'high'
    }>
  }
  error?: string
}

Usage:

import { analyzeFace } from '@/app/actions/scan'

const formData = new FormData()
formData.append('file', faceImage)

const result = await analyzeFace(formData)

generateRiskAssessment(formData: FormData)

Generates a comprehensive health risk assessment.

Parameters:

FieldTypeRequiredDescription
agestringYesUser's age
genderstringYesUser's gender
symptomsstringNoCurrent symptoms description
medicalHistorystringNoPast medical history
medicationsstringNoCurrent medications
reportAnalysisIdstringNoID of report analysis to include
faceAnalysisIdstringNoID of face analysis to include

Returns:

interface RiskAssessmentResult {
  success: boolean
  data?: {
    id: string
    assessment: string  // Markdown formatted assessment
    createdAt: Date
  }
  error?: string
}

Usage:

import { generateRiskAssessment } from '@/app/actions/scan'

const formData = new FormData()
formData.append('age', '45')
formData.append('gender', 'male')
formData.append('symptoms', 'Fatigue, occasional headaches')
formData.append('reportAnalysisId', 'analysis_123')

const result = await generateRiskAssessment(formData)

Chatbot Actions (/app/actions/chatbot.ts)

getChatbotContext()

Retrieves context data for the AI chatbot including user profile and analysis history.

Returns:

interface ChatbotContext {
  user: {
    id: string
    name: string
    email: string
    createdAt: Date
  }
  analyses: Array<{
    id: string
    type: 'face' | 'report' | 'risk'
    createdAt: Date
    structuredData: any
    visualMetrics?: any
    riskAssessment?: string
  }>
  platformKnowledge: string
}

Usage:

import { getChatbotContext } from '@/app/actions/chatbot'

const context = await getChatbotContext()
// Use context to build AI prompt

Profile Actions (/app/actions/profile.ts)

updateProfile(formData: FormData)

Updates user profile information.

Parameters:

FieldTypeRequiredDescription
namestringNoDisplay name
preferencesJSONNoUser preferences object

Returns:

interface UpdateProfileResult {
  success: boolean
  error?: string
}

REST API Endpoints

Analysis Endpoints

POST /api/analyze/report

Analyzes a medical report document.

Request:

POST /api/analyze/report
Content-Type: multipart/form-data
Authorization: Bearer <token>

file: <binary file data>

Response:

{
  "success": true,
  "analysisId": "clx123abc456",
  "data": {
    "raw_text": "...",
    "structured_data": {
      "metrics": [...],
      "problems_detected": [...],
      "treatments": [...]
    }
  }
}

Error Response:

{
  "success": false,
  "error": "File too large. Maximum size is 10MB."
}

POST /api/analyze/face

Analyzes a face photo for health indicators.

Request:

POST /api/analyze/face
Content-Type: multipart/form-data
Authorization: Bearer <token>

file: <binary image data>

Response:

{
  "success": true,
  "analysisId": "clx789def012",
  "data": {
    "face_detected": true,
    "face_count": 1,
    "visual_metrics": {
      "redness_percentage": 25,
      "yellowness_percentage": 10,
      "skin_tone": "medium"
    },
    "problems_detected": [...],
    "treatments": [...]
  }
}

POST /api/analyze/risk

Generates a comprehensive risk assessment.

Request:

POST /api/analyze/risk
Content-Type: application/json
Authorization: Bearer <token>

{
  "age": 45,
  "gender": "male",
  "symptoms": "Fatigue, headaches",
  "medicalHistory": "Hypertension",
  "medications": "Lisinopril 10mg",
  "reportAnalysisId": "clx123abc456",
  "faceAnalysisId": "clx789def012"
}

Response:

{
  "success": true,
  "analysisId": "clx456ghi789",
  "data": {
    "assessment": "# Health Risk Assessment\n\n## Risk Factors...",
    "createdAt": "2024-01-15T10:30:00Z"
  }
}

Analyses CRUD Endpoints

GET /api/analyses

Retrieves user's analysis history.

Query Parameters:

ParameterTypeDefaultDescription
typestringallFilter by type: face, report, risk
pagenumber1Page number for pagination
limitnumber20Items per page

Request:

GET /api/analyses?type=report&page=1&limit=10
Authorization: Bearer <token>

Response:

{
  "success": true,
  "data": {
    "analyses": [
      {
        "id": "clx123abc456",
        "type": "report",
        "createdAt": "2024-01-15T10:30:00Z",
        "structuredData": {...}
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 25,
      "totalPages": 3
    }
  }
}

GET /api/analyses/[id]

Retrieves a specific analysis by ID.

Request:

GET /api/analyses/clx123abc456
Authorization: Bearer <token>

Response:

{
  "success": true,
  "data": {
    "id": "clx123abc456",
    "type": "report",
    "createdAt": "2024-01-15T10:30:00Z",
    "rawData": {...},
    "structuredData": {...},
    "problemsDetected": [...],
    "treatments": [...]
  }
}

DELETE /api/analyses/[id]

Deletes an analysis.

Request:

DELETE /api/analyses/clx123abc456
Authorization: Bearer <token>

Response:

{
  "success": true,
  "message": "Analysis deleted successfully"
}

Chatbot Endpoint

POST /api/chatbot

Sends a message to the AI health assistant.

Request:

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

{
  "message": "What did my last blood test show?",
  "conversationHistory": [
    {
      "role": "user",
      "content": "Hello"
    },
    {
      "role": "assistant",
      "content": "Hello! How can I help you today?"
    }
  ]
}

Response:

{
  "success": true,
  "data": {
    "response": "Based on your last blood test from January 15th...",
    "timestamp": "2024-01-15T11:00:00Z"
  }
}

User Endpoints

POST /api/register

Registers a new user (for custom auth fallback).

Request:

POST /api/register
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "securePassword123",
  "name": "John Doe"
}

Response:

{
  "success": true,
  "message": "User registered successfully",
  "userId": "clx123user456"
}

POST /api/forgot-password

Initiates password reset process.

Request:

POST /api/forgot-password
Content-Type: application/json

{
  "email": "user@example.com"
}

Response:

{
  "success": true,
  "message": "If an account exists, a reset email has been sent"
}

Error Handling

Standard Error Response Format

All API errors follow a consistent format:

{
  "success": false,
  "error": "Human-readable error message",
  "code": "ERROR_CODE",
  "details": {}
}

HTTP Status Codes

CodeMeaningWhen Used
200OKSuccessful request
201CreatedResource created
400Bad RequestInvalid input data
401UnauthorizedMissing or invalid auth
403ForbiddenInsufficient permissions
404Not FoundResource not found
413Payload Too LargeFile exceeds size limit
429Too Many RequestsRate limit exceeded
500Server ErrorInternal error

Error Codes

CodeDescription
AUTH_REQUIREDAuthentication required
AUTH_INVALIDInvalid authentication token
FILE_TOO_LARGEFile exceeds maximum size
FILE_TYPE_INVALIDUnsupported file type
ANALYSIS_NOT_FOUNDRequested analysis doesn't exist
AI_SERVICE_ERRORAI service unavailable
RATE_LIMIT_EXCEEDEDToo many requests
VALIDATION_ERRORInput validation failed

Error Handling in Client

async function callAPI() {
  try {
    const response = await fetch('/api/analyze/report', {
      method: 'POST',
      body: formData
    })

    if (!response.ok) {
      const error = await response.json()

      switch (response.status) {
        case 401:
          // Redirect to login
          break
        case 413:
          // Show file size error
          break
        case 429:
          // Show rate limit message
          break
        default:
          // Show generic error
      }
      return
    }

    const data = await response.json()
    // Handle success
  } catch (error) {
    // Network error
  }
}

Rate Limiting

Limits

EndpointRate LimitWindow
/api/analyze/*10 requests1 minute
/api/chatbot20 requests1 minute
/api/analyses60 requests1 minute
All endpoints100 requests1 minute

Rate Limit Headers

Responses include rate limit information:

X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1705320000

Handling Rate Limits

When rate limited, the API returns:

HTTP/1.1 429 Too Many Requests
Retry-After: 45

{
  "success": false,
  "error": "Rate limit exceeded. Please try again in 45 seconds.",
  "code": "RATE_LIMIT_EXCEEDED"
}

TypeScript Types

Common Types

// Analysis types
type AnalysisType = 'face' | 'report' | 'risk'

// Severity levels
type Severity = 'low' | 'moderate' | 'high' | 'critical'

// Metric status
type MetricStatus = 'normal' | 'low' | 'high' | 'critical'

// Priority levels
type Priority = 'low' | 'medium' | 'high'

// Base analysis interface
interface Analysis {
  id: string
  userId: string
  type: AnalysisType
  rawData: any
  structuredData?: any
  visualMetrics?: any
  riskAssessment?: string
  problemsDetected?: any
  treatments?: any
  createdAt: Date
}

// API Response wrapper
interface ApiResponse<T> {
  success: boolean
  data?: T
  error?: string
  code?: string
}

Import Types

import type {
  Analysis,
  AnalysisType,
  Severity,
  MetricStatus,
  Priority,
  ApiResponse
} from '@/types'

SDK/Client Examples

Fetch Wrapper

class SehatScanClient {
  private baseUrl: string
  private token: string

  constructor(token: string) {
    this.baseUrl = process.env.NEXT_PUBLIC_APP_URL || ''
    this.token = token
  }

  private async request<T>(
    endpoint: string,
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        Authorization: `Bearer ${this.token}`,
        ...options.headers
      }
    })

    return response.json()
  }

  async analyzeReport(file: File) {
    const formData = new FormData()
    formData.append('file', file)

    return this.request('/api/analyze/report', {
      method: 'POST',
      body: formData
    })
  }

  async getAnalyses(type?: AnalysisType) {
    const params = type ? `?type=${type}` : ''
    return this.request(`/api/analyses${params}`)
  }
}

Webhooks (Future)

Webhook support for async notifications is planned:

  • analysis.completed - Analysis finished processing
  • risk.generated - Risk assessment generated
  • alert.health - Health alert triggered

Configuration will be available in dashboard settings.