# Vault - API Contracts **Generated:** 2026-02-11 **Framework:** Next.js 15 App Router --- ## API Overview Vault uses Next.js 15 App Router with two primary patterns: 1. **API Routes** - Traditional REST endpoints (`src/app/api/`) 2. **Server Actions** - Form mutations with progressive enhancement (`'use server'`) --- ## API Routes ### Authentication #### `POST /api/auth/[...all]` Better Auth handler for all authentication endpoints. **Handled by:** [`src/app/api/auth/[...all]/route.ts`](../src/app/api/auth/[...all]/route.ts) **Endpoints:** - `POST /api/auth/sign-in/email` - Email/password sign in - `POST /api/auth/sign-up/email` - Email/password registration - `GET /api/auth/session` - Get current session - `POST /api/auth/sign-out` - Sign out - `GET /api/auth/callback/google` - Google OAuth callback --- ### Inngest #### `POST /api/inngest` Inngest webhook handler for background job execution. **Handled by:** [`src/app/api/inngest/route.ts`](../src/app/api/inngest/route.ts) **Registered Functions:** - `scan-video-archive` - YouTube archive scanning - `detect-objects` - AI object detection - `match-marketplace` - Marketplace product matching - `monitor-link-health` - Link health monitoring - `checkSingleLinkHealth` - Single link check - `warmFeaturedCreatorsCache` - Cache warming - `healSocialMetadata` - Social metadata repair **Authentication:** Requires `INNGEST_SIGNING_KEY` in production. --- ### YouTube Integration #### `GET /api/youtube/connect` Initiates YouTube OAuth flow. **Handled by:** [`src/app/api/youtube/connect/route.ts`](../src/app/api/youtube/connect/route.ts) **Response:** Redirects to Google OAuth consent screen. #### `GET /api/youtube/callback` Handles YouTube OAuth callback. **Handled by:** [`src/app/api/youtube/callback/route.ts`](../src/app/api/youtube/callback/route.ts) **Query Parameters:** - `code` - OAuth authorization code - `state` - CSRF state token **Response:** Redirects to dashboard with connection status. #### `POST /api/youtube/disconnect` Disconnects YouTube channel. **Handled by:** [`src/app/api/youtube/disconnect/route.ts`](../src/app/api/youtube/disconnect/route.ts) **Response:** JSON with success status. --- ### Health Check #### `GET /api/health` Health check endpoint for monitoring. **Handled by:** [`src/app/api/health/route.ts`](../src/app/api/health/route.ts) **Response:** ```json { "status": "ok", "timestamp": "2026-02-11T20:00:00.000Z" } ``` --- ### Manual Triggers (Development) #### `POST /api/manual-trigger` Manually trigger Inngest functions (development only). **Handled by:** [`src/app/api/manual-trigger/route.ts`](../src/app/api/manual-trigger/route.ts) --- ## Server Actions Server Actions are defined with `'use server'` directive and called directly from client components. ### Discovery Actions #### `connectYouTubeAction()` Initiates YouTube connection flow. **File:** [`src/features/discovery/actions/connect-youtube.ts`](../src/features/discovery/actions/connect-youtube.ts) **Returns:** ```typescript { success: boolean; error?: string; } ``` --- ### Vault Actions #### `redirectToMarketplace(matchId, viewerIp, userAgent, referrer)` Tracks and redirects to marketplace affiliate link. **File:** [`src/features/vault/actions/redirect-to-marketplace.ts`](../src/features/vault/actions/redirect-to-marketplace.ts) **Parameters:** - `matchId: string` - Marketplace match ID - `viewerIp?: string` - Anonymized viewer IP - `userAgent?: string` - Client user agent - `referrer?: string` - Referrer URL **Returns:** ```typescript { success: boolean; url?: string; error?: string; } ``` #### `searchProducts(query, creatorSlug)` Search products across creator's vault. **File:** [`src/features/vault/actions/search-products.ts`](../src/features/vault/actions/search-products.ts) **Parameters:** - `query: string` - Search query - `creatorSlug: string` - Creator's URL slug **Returns:** ```typescript { success: boolean; products?: ProductCard[]; error?: string; } ``` #### `triggerAnalysis(videoId, videoUrl)` Trigger AI analysis for a video. **File:** [`src/features/vault/actions/trigger-analysis.ts`](../src/features/vault/actions/trigger-analysis.ts) **Parameters:** - `videoId: string` - Internal video ID - `videoUrl: string` - Video URL for processing **Returns:** ```typescript { success: boolean; error?: string; } ``` #### `quickAnalyze(videoUrl)` Quick analysis tool for arbitrary video URLs. **File:** [`src/features/vault/actions/quick-analyze.ts`](../src/features/vault/actions/quick-analyze.ts) --- ### Moderation Actions #### `approveDetection(detectionId)` Approve a detected object for vault display. **File:** [`src/features/moderation/actions/approve-detection.ts`](../src/features/moderation/actions/approve-detection.ts) **Parameters:** - `detectionId: string` - Detection ID **Returns:** ```typescript { success: boolean; error?: string; } ``` #### `rejectDetection(detectionId)` Reject a detected object. **File:** [`src/features/moderation/actions/reject-detection.ts`](../src/features/moderation/actions/reject-detection.ts) **Parameters:** - `detectionId: string` - Detection ID **Returns:** ```typescript { success: boolean; error?: string; } ``` #### `bulkApprove(detectionIds)` Approve multiple detections at once. **File:** [`src/features/moderation/actions/bulk-approve.ts`](../src/features/moderation/actions/bulk-approve.ts) **Parameters:** - `detectionIds: string[]` - Array of detection IDs **Returns:** ```typescript { success: boolean; approved: number; failed: number; error?: string; } ``` #### `bulkReject(detectionIds)` Reject multiple detections at once. **File:** [`src/features/moderation/actions/bulk-reject.ts`](../src/features/moderation/actions/bulk-reject.ts) #### `editDetection(detectionId, updates)` Edit detection details (name, category, thumbnail). **File:** [`src/features/moderation/actions/edit-detection.ts`](../src/features/moderation/actions/edit-detection.ts) **Parameters:** - `detectionId: string` - Detection ID - `updates: { objectName?, category?, thumbnailUrl? }` - Fields to update **Returns:** ```typescript { success: boolean; error?: string; } ``` #### `deleteDetection(detectionId)` Permanently delete a detection. **File:** [`src/features/moderation/actions/delete-detection.ts`](../src/features/moderation/actions/delete-detection.ts) #### `addDetection(videoId, data)` Manually add a product detection to a video. **File:** [`src/features/moderation/actions/add-detection.ts`](../src/features/moderation/actions/add-detection.ts) **Parameters:** - `videoId: string` - Video ID - `data: { objectName, category, frameTimestamp?, thumbnailUrl?, marketplaceMatches? }` --- ### Admin Moderation Actions #### `adminCorrectDetection(detectionId, corrections)` Admin correction with audit trail. **File:** [`src/features/moderation/actions/admin-correct-detection.ts`](../src/features/moderation/actions/admin-correct-detection.ts) **Parameters:** - `detectionId: string` - Detection ID - `corrections: { objectName?, category? }` - Corrected values **Returns:** ```typescript { success: boolean; error?: string; } ``` #### `adminMarkIncorrect(detectionId, reasonCode)` Mark detection as incorrect with reason. **File:** [`src/features/moderation/actions/admin-mark-incorrect.ts`](../src/features/moderation/actions/admin-mark-incorrect.ts) **Parameters:** - `detectionId: string` - Detection ID - `reasonCode: 'wrong_object' | 'wrong_category' | 'false_positive' | 'unclear_image' | 'duplicate' | 'out_of_scope'` --- ### Marketplace Actions #### `triggerMarketplaceMatch(objectId)` Trigger marketplace matching for a detection. **File:** [`src/features/marketplace/actions/trigger-marketplace-match.ts`](../src/features/marketplace/actions/trigger-marketplace-match.ts) **Parameters:** - `objectId: string` - Detection ID **Returns:** ```typescript { success: boolean; matchCount?: number; error?: string; } ``` #### `triggerLinkHealthCheck(matchId)` Check health of a specific affiliate link. **File:** [`src/features/marketplace/actions/trigger-link-health-check.ts`](../src/features/marketplace/actions/trigger-link-health-check.ts) --- ### Interest Actions #### `createInterestPledge(marketplaceMatchId, email, detectedObjectId)` Create an interest pledge for out-of-stock item. **File:** [`src/features/interest/actions/create-interest-pledge.ts`](../src/features/interest/actions/create-interest-pledge.ts) **Parameters:** - `marketplaceMatchId: string | null` - Match ID - `email: string` - User email - `detectedObjectId: string | null` - Detection ID **Returns:** ```typescript { success: boolean; isDuplicate?: boolean; error?: string; } ``` --- ### Request & Proposal Actions #### `submitRequest(videoId, data)` Submit a product request for a video. **File:** [`src/actions/submit-request.ts`](../src/actions/submit-request.ts) **Parameters:** - `videoId: string` - Video ID - `data: { viewerName?, viewerEmail?, note, imageUrl?, frameTimestamp? }` #### `submitProposal(videoId, data)` Submit an affiliate link proposal. **File:** [`src/actions/submit-proposal.ts`](../src/actions/submit-proposal.ts) **Parameters:** - `videoId: string` - Video ID - `data: { productUrl, affiliateUrl, productName, price?, imageUrl?, note?, objectId? }` #### `handleProposal(proposalId, action)` Approve or reject a proposal. **File:** [`src/features/moderation/actions/handle-proposal.ts`](../src/features/moderation/actions/handle-proposal.ts) **Parameters:** - `proposalId: string` - Proposal ID - `action: 'approve' | 'reject'` - Action to take --- ### Claim Actions #### `claimVideo(videoId, creatorId)` Claim ownership of a video. **File:** [`src/actions/claim-video.ts`](../src/actions/claim-video.ts) --- ## Data Fetching Patterns ### Server-Side Rendering (SSR) Pages fetch data directly in async server components: ```typescript // src/app/vault/[creatorSlug]/page.tsx export default async function VaultPage({ params }) { const vault = await VaultService.getCreatorVault(params.creatorSlug); return ; } ``` ### Incremental Static Regeneration (ISR) Pages can use ISR for caching: ```typescript export const revalidate = 300; // 5 minutes ``` ### Client-Side Fetching Client components use SWR or direct server action calls: ```typescript // Using server action const result = await approveDetection(detectionId); if (result.success) { toast.success('Detection approved'); } ``` --- ## Error Handling All server actions follow a consistent error pattern: ```typescript { success: boolean; error?: string; // Additional fields as needed } ``` Errors are captured with Sentry: ```typescript import * as Sentry from '@sentry/nextjs'; catch (error) { Sentry.captureException(error, { tags: { action: 'action-name', resource_id: id }, }); return { success: false, error: 'Failed to perform action' }; } ``` --- ## Authentication & Authorization ### Session Access ```typescript import { auth } from '@/lib/auth'; import { headers } from 'next/headers'; const session = await auth.api.getSession({ headers: await headers(), }); ``` ### Authorization Pattern ```typescript // Verify ownership const detection = await db.query.detectedObjects.findFirst({ where: eq(detectedObjects.id, detectionId), }); if (detection.creatorId !== session.user.id) { return { success: false, error: 'Unauthorized' }; } ``` ### Admin Check ```typescript const adminEmails = process.env.ADMIN_EMAILS?.split(',') || []; const isAdmin = session.user.email && adminEmails.includes(session.user.email); ``` --- ## Related Documentation - [Data Models](./data-models.md) - Database schema - [Inngest Workflows](./inngest-workflows.md) - Background jobs - [Development Guide](./development-guide.md) - Setup instructions