All REST API endpoints and usage
API Reference
All API routes live under src/app/api/. They are Next.js App Router route handlers using the standard GET, POST, etc. export convention.
Authentication
Frame.io OAuth
GET /api/auth/frameio
Initiates the Frame.io OAuth flow by redirecting to Adobe IMS with the configured client ID and scopes.
GET /api/auth/frameio/callback
Handles the OAuth callback. Exchanges the authorization code for access/refresh tokens and stores them in HTTP-only cookies.
Video Processing & Storage
POST /api/clips/store
Fetches a processed clip from the Modal API (with retry logic), uploads the video to Supabase Storage (session-videos bucket), and saves the stats JSON to the clip record. Requires authentication -- verifies the caller owns the clip via coach_id.
Body:
{
"clipId": "uuid"
}
POST /api/sessions/store
Similar to clip store but operates at the session level. Fetches the processed session video from Modal, uploads to Supabase Storage, and saves stats. Requires authentication -- verifies the caller owns the session via coach_id.
Body:
{
"sessionId": "uuid"
}
GET /api/video/sign
Generates an HMAC-signed stream URL for a given upstream video URL. Requires authentication. The signed URL has a 1-hour TTL.
Query params:
| Param | Description |
|---|---|
url | The upstream video URL to sign for streaming |
Response: { "url": "/api/video/stream?url=...&expires=...&token=..." }
GET /api/video/stream
Video stream proxy with byte-range support. Proxies video from allowlisted hosts (Modal, Supabase, Frame.io) to the client. Handles Range headers for seeking. Requires a valid HMAC token (obtained from /api/video/sign).
Query params:
| Param | Description |
|---|---|
url | The source video URL to proxy |
token | HMAC signature (from /api/video/sign) |
expires | Token expiry timestamp in ms |
Frame.io Integration
All Frame.io endpoints require a valid OAuth token stored in the frameio_token cookie. Returns 401 if the token is missing or expired.
GET /api/frameio/me
Returns the current Frame.io user profile.
GET /api/frameio/projects
Lists workspaces or projects for an account.
Query params:
| Param | Description |
|---|---|
accountId | The Frame.io account ID |
GET /api/frameio/assets
Lists children (files and folders) of a given folder.
Query params:
| Param | Description |
|---|---|
folderId | The Frame.io folder/asset ID |
POST /api/frameio/import
Imports files from Frame.io into Surflink. Downloads assets, creates a session with clips, and sends each clip to Modal for AI analysis.
Body:
{
"assets": [{ "id": "asset-id", "name": "clip.mp4" }],
"sessionTitle": "Morning Session"
}
Limits: Max 10 clips per import, 5-minute timeout.
Surf Conditions
GET /api/surf/forecast
Returns surf conditions for all Barbados spots.
Query params:
| Param | Description |
|---|---|
detail | If true, fetches individual spot data (slower, more detailed) |
coast | Filter by coast (e.g., west, south) |
minWave | Minimum wave height filter (feet) |
GET /api/surf/spot/[slug]
Returns detailed forecast for a single surf spot.
Query params:
| Param | Description |
|---|---|
days | Number of forecast days (1-6, default 1) |
Response includes: wave height/period/direction, wind speed/direction/gusts, surf rating, tide data.
Achievements
POST /api/achievements/check
Evaluates 20+ achievement rules for a student and awards any newly earned badges.
Body:
{
"studentId": "uuid"
}
POST /api/achievements/seed
Seeds the achievements table with all achievement definitions. Idempotent -- safe to call multiple times.
Notifications
POST /api/notifications/send
Creates a notification record in the database and optionally sends:
- APNs push to registered iOS/watchOS devices
- Email via Resend for critical notification types (lesson reminders, achievements)
Body:
{
"userId": "uuid",
"type": "lesson_reminder",
"title": "Lesson Tomorrow",
"body": "You have a lesson scheduled for 9am at Freights."
}
Invitations
POST /api/invite
Generates an invite token for a student and optionally sends an email invitation via Resend.
Body:
{
"studentId": "uuid",
"sendEmail": true
}
Returns the invite URL that the student can use to accept and create their account.