# 04 — API Reference

This document covers all Next.js route handlers (`app/api/`) and key server actions (`features/*/api/`).

> **Authentication:** All protected endpoints require a valid Clerk session. Unauthenticated requests receive a `401 Unauthorized` response. Route-level protection is enforced by `proxy.ts` (Clerk middleware).

---

## Route Handlers (`app/api/`)

### `POST /api/uploadthing`
**File:** `app/api/uploadthing/route.ts`  
**Purpose:** UploadThing file upload endpoint. Handles authenticated file uploads and triggers contract creation.

**Constraints:**
- Max file size: 32 MB
- Accepted types: `application/pdf`, `image/jpeg`, `image/png`, `image/webp`
- Authentication: Clerk session required

**Flow:**
1. UploadThing middleware validates the session via Clerk
2. File is stored on UploadThing CDN
3. On completion, returns `{ fileUrl, fileName, fileSize, mimeType }` to the client

---

### `POST /api/webhooks/clerk`
**File:** `app/api/webhooks/clerk/route.ts`  
**Purpose:** Receives Clerk lifecycle events and syncs user data to PostgreSQL.

**Verification:** Request signature verified via Svix + `CLERK_WEBHOOK_SECRET`

**Handled Events:**

| Event | Action |
|-------|--------|
| `user.created` | Creates a new `User` record in PostgreSQL |
| `user.updated` | Updates `email`, `firstName`, `lastName`, `imageUrl` |
| `user.deleted` | Deletes `User` record (cascades to contracts, notifications) |

**Response:** `200 OK` on success, `400 Bad Request` if signature invalid.

---

### `GET /api/contracts/[id]/download`
**File:** `app/api/contracts/[id]/download/route.ts`  
**Purpose:** Proxies contract file download through the server (adds auth check before serving).

**Authentication:** Clerk session + ownership validation  
**Response:** File stream with appropriate `Content-Type` and `Content-Disposition` headers.

---

## Server Actions (`features/contracts/api/contract.action.ts`)

All server actions are decorated with `"use server"` and perform double authentication (Clerk session + DB ownership check).

---

### `saveContract(data)`

Saves a new contract after UploadThing upload, then **automatically triggers AI analysis**.

**Parameters:**
```typescript
{
  fileName: string
  fileUrl: string
  fileSize: number
  mimeType: string
}
```

**Returns:**
```typescript
{ success: true, contract: Contract } |
{ success: true, contract: Contract, analysisSuccess: false, analysisError: string } |
{ success: false, error: string }
```

**Side effects:**
- Creates `Contract` record (status: `UPLOADED`)
- Creates in-app notification (upload success)
- Triggers `analyzeContractAction()` automatically
- Revalidates `/contacts` and `/dashboard`

---

### `getContracts(filters?)`

Returns all contracts for the authenticated user with optional filtering.

**Parameters:**
```typescript
{
  status?: ContractStatus
  type?: ContractType
  search?: string    // searches title, provider, policyNumber, fileName
}
```

**Returns:**
```typescript
{
  success: true,
  contracts: SerializedContract[]
}
```

**Serialization:** `Decimal` → `number`, `Date` → ISO string

---

### `getContract(id)`

Returns a single contract by ID.

**Parameters:** `id: string` (contract ID)

**Returns:** `{ success: true, contract: Contract } | { success: false, error: string }`

---

### `deleteContract(id)`

Permanently deletes a contract (ownership validated, cascades to RAG chunks and notifications).

**Returns:** `{ success: true } | { success: false, error: string }`

**Side effects:**
- Deletes file from UploadThing CDN
- Cascades delete to `ContractRagChunk`, `Notification`, `BlockchainTransaction`
- Creates in-app notification (delete success)
- Revalidates `/contacts` and `/dashboard`

---

### `deleteAllContractsAction()`

Deletes all contracts for the authenticated user.

**Returns:** `{ success: true, deletedCount: number } | { success: false, error: string }`

---

### `analyzeContractAction(id)`

Triggers the full AI analysis pipeline for a contract.

**Parameters:** `id: string` (contract ID)

**Returns:**
```typescript
{ success: true, contract: NormalizedAnalysis } |
{
  success: false,
  error: string,
  errorCode: "INVALID_CONTRACT" | "ANALYSIS_ERROR"
}
```

**Pipeline:**
1. Set status → `PROCESSING`
2. Run AI extraction (Gemini → Mistral fallback)
3. Validate AI output
4. Save extracted fields to DB
5. Build RAG chunks (embeddings)
6. Register document hash on blockchain (non-blocking)
7. Send analysis complete email (non-blocking)
8. Create in-app notification
9. Set status → `COMPLETED`

**Error codes:**
- `INVALID_CONTRACT` — uploaded file is not a recognized contract document
- `ANALYSIS_ERROR` — analysis pipeline failed (AI error, parse error, etc.)

---

### `askContractQuestionAction(id, question)`

Answers a natural-language question about a specific contract using RAG + AI.

**Parameters:**
```typescript
id: string        // contract ID
question: string  // user's question
```

**Returns:**
```typescript
{ success: true, answer: string } |
{ success: false, error: string }
```

**Pipeline:**
1. Load contract from DB
2. RAGService retrieves top-6 most relevant chunks
3. AIService sends question + contract context + RAG chunks to Gemini
4. Sanitized answer returned to UI

---

### `getContractStats()`

Returns analytics data for the dashboard.

**Returns:**
```typescript
{
  success: true,
  stats: {
    total: number
    byStatus: Record<ContractStatus, number>
    byType: Record<ContractType, number>
    byMonth: Array<{ month: string, count: number }>
    expiringSoon: number
    averagePremium: number | null
    blockchainCoverage: number  // percentage
  }
}
```

---

## Notification Server Actions

**File:** `features/notifications/api/` (or `lib/services/notification.service.ts`)

### `getNotificationsAction()`
Returns all unread (and recent read) notifications for the user.

### `markNotificationReadAction(id)`
Marks a single notification as read.

### `markAllNotificationsReadAction()`
Marks all notifications as read.

### `deleteNotificationAction(id)`
Deletes a single notification.

---

## Blockchain Server Actions

**File:** `features/blockchain/api/`

### `getBlockchainStatsAction()`
Returns network stats: total verified docs, block number, network name, connection status.

### `verifyDocumentAction(documentHash)`
Verifies whether a given SHA-256 hash is registered on-chain.

**Returns:**
```typescript
{
  exists: boolean
  timestamp: number      // Unix timestamp
  depositor: string      // Ethereum address
  formattedDate: string  // Human-readable date
}
```

---

## Health Check Endpoint

The Dockerfile `HEALTHCHECK` calls:
```
GET /api/health
```

This route should return `200 OK` with `{ status: "ok" }`.  
If this route does not exist, create it at `app/api/health/route.ts`:

```typescript
export async function GET() {
  return Response.json({ status: "ok" });
}
```
