Skip to content

API Reference

Changemaker Lite exposes two REST APIs sharing a single PostgreSQL database.

Server Framework Port Purpose
Main API Express.js 4000 Auth, campaigns, map, shifts, canvassing, pages, email, settings
Media API Fastify 4100 Video library, analytics, playlists, reactions, comments

Both APIs use JWT Bearer authentication and return JSON. All request/response bodies are application/json unless noted otherwise.


Authentication

Token Flow

sequenceDiagram
    participant Client
    participant API
    participant DB

    Client->>API: POST /api/auth/login {email, password}
    API->>DB: Verify credentials
    DB-->>API: User record
    API-->>Client: {accessToken, refreshToken}
    Note over Client: Store tokens

    Client->>API: GET /api/campaigns (Authorization: Bearer <accessToken>)
    API-->>Client: 200 OK

    Note over Client: Access token expires (15 min)

    Client->>API: POST /api/auth/refresh {refreshToken}
    API->>DB: Rotate token (atomic transaction)
    DB-->>API: New token pair
    API-->>Client: {accessToken, refreshToken}

Headers

All authenticated requests require:

Authorization: Bearer <accessToken>

The Media API also accepts tokens via query parameter for SSE streams:

GET /api/public/:id/chat-stream?token=<accessToken>

Roles

Role Access Level
SUPER_ADMIN Full platform access
INFLUENCE_ADMIN Campaign and advocacy management
MAP_ADMIN Map, locations, shifts, canvassing
USER Volunteer portal, public features
TEMP Limited access (auto-created on public shift signup)

Middleware Reference

Middleware Effect
authenticate Requires valid JWT. Sets req.user with id, email, role. Returns 401 if missing or invalid.
optionalAuth Same as authenticate but continues without user if token is absent.
requireRole(...roles) Checks user role against allowed list. Returns 403 if not authorized.
requireNonTemp Blocks TEMP users. Returns 403.
validate(schema, source) Validates request body/query/params against a Zod schema. Returns 400 on failure.

Error Responses

All errors follow a consistent format:

{
  "error": {
    "message": "Human-readable error description",
    "code": "ERROR_CODE",
    "statusCode": 400
  }
}
Status Code Meaning
400 VALIDATION_ERROR Request body/query failed schema validation
401 UNAUTHORIZED Missing or invalid access token
403 FORBIDDEN Valid token but insufficient role
404 NOT_FOUND Resource does not exist
429 RATE_LIMITED Too many requests (see Rate Limits)
500 INTERNAL_ERROR Unexpected server error

Enumeration Prevention

Auth endpoints (/login, /register, /forgot-password) return generic success messages to prevent user enumeration. A 401 from /api/auth/me does not reveal whether the user exists.


Rate Limits

Rate limits are Redis-backed and keyed by IP address.

Endpoint Group Window Max Requests Redis Prefix
Auth (login, register, refresh) 15 min 10 rl:auth:
Email sending 1 hour 30 rl:email:
Response submission 1 hour 10 rl:response:
Shift signup 1 hour 10 rl:shift-signup:
Canvass visits 1 min 30 rl:canvass-visit:
Canvass bulk visits 1 min 5 rl:canvass-visit-bulk:
GPS tracking 1 min 6 rl:gps-tracking:
Canvass geocode 1 min 10 rl:canvass-geocode:
Observability 1 min 20 rl:observability:
Health/metrics 1 min 30 rl:health-metrics:
Global (all other) Configurable Configurable rl:global:

When rate-limited, the API returns:

{
  "error": {
    "message": "Too many requests, please try again later",
    "code": "RATE_LIMITED",
    "statusCode": 429
  }
}

Main API (Express — Port 4000)

Health & Metrics

Method Path Auth Description
GET /api/health Health check — PostgreSQL + Redis ping
GET /api/metrics Prometheus metrics (text/plain)
Health response
{
  "status": "healthy",
  "checks": {
    "database": "ok",
    "redis": "ok"
  }
}

Auth

Prefix: /api/auth

Method Path Auth Rate Limited Description
POST /api/auth/login Email + password login
POST /api/auth/register Create account (always USER role)
POST /api/auth/verify-email Verify email with token
POST /api/auth/resend-verification Resend verification email
POST /api/auth/forgot-password Send password reset email
POST /api/auth/reset-password Set new password with reset token
POST /api/auth/refresh Rotate refresh token → new token pair
POST /api/auth/logout Invalidate refresh token
GET /api/auth/me Current user profile
Login request & response

Request:

{
  "email": "admin@example.com",
  "password": "SecurePass123!"
}
Response:
{
  "accessToken": "eyJhbG...",
  "refreshToken": "eyJhbG...",
  "user": {
    "id": "uuid",
    "email": "admin@example.com",
    "name": "Admin",
    "role": "SUPER_ADMIN"
  }
}

Password Policy

Passwords must be at least 12 characters with at least one uppercase letter, one lowercase letter, and one digit.


Users

Prefix: /api/users · Auth: All routes require authentication

Method Path Role Description
GET /api/users Admin Paginated user list with search, role, and status filters
GET /api/users/:id Admin or self Single user profile
POST /api/users Admin Create user
PUT /api/users/:id Admin or self Update user (non-admins cannot change role/status)
POST /api/users/:id/approve Admin Approve pending user; sends approval email
POST /api/users/:id/reject Admin Reject pending user
DELETE /api/users/:id Admin Delete user

Query parameters for GET /api/users:

Param Type Description
page number Page number (default 1)
limit number Items per page (default 20)
search string Search by name or email
role string Filter by role
status string Filter by status

Dashboard

Prefix: /api/dashboard · Auth: Admin roles required

Method Path Role Description
GET /api/dashboard/summary Any admin Platform-wide counts (users, campaigns, locations, shifts)
GET /api/dashboard/system SUPER_ADMIN Hardware + OS info (CPU, memory, disk)
GET /api/dashboard/containers SUPER_ADMIN Docker container statuses
GET /api/dashboard/weather Any admin Current weather at map center coordinates
GET /api/dashboard/api-metrics SUPER_ADMIN Prometheus API performance metrics
GET /api/dashboard/time-series SUPER_ADMIN Prometheus time-series data
GET /api/dashboard/container-resources SUPER_ADMIN cAdvisor CPU/memory/network per container

Query parameters for GET /api/dashboard/time-series:

Param Type Description
metrics string Comma-separated metric keys (whitelist-validated)
range string Time range (e.g., 1h, 24h, 7d)
step string Sample interval (e.g., 5m, 1h)

Campaigns

Admin CRUD

Prefix: /api/campaigns · Auth: Admin roles

Method Path Description
GET /api/campaigns Paginated campaign list
GET /api/campaigns/:id Single campaign detail
POST /api/campaigns Create campaign
PUT /api/campaigns/:id Update campaign
DELETE /api/campaigns/:id Delete campaign

Public

Method Path Auth Description
GET /api/campaigns/public List all active campaigns
GET /api/campaigns/:slug/details Campaign detail by slug (ACTIVE only)

User Submissions

Auth: Authenticated, non-TEMP users

Method Path Description
POST /api/campaigns/user/submit Submit campaign for moderation (5/hour limit)
GET /api/campaigns/user/my-campaigns List own submitted campaigns
PUT /api/campaigns/user/:id Edit own pending campaign

Moderation

Auth: Admin roles

Method Path Description
GET /api/campaigns/moderation/queue Campaigns pending moderation
GET /api/campaigns/moderation/stats Moderation queue statistics
PATCH /api/campaigns/moderation/:id Approve or reject campaign

Campaign Emails

Method Path Auth Description
POST /api/campaigns/:slug/send-email Send advocacy email to representatives (rate limited: 30/hour)
POST /api/campaigns/:slug/track-mailto Track mailto link click
GET /api/campaigns/:id/emails Admin Paginated emails for campaign
GET /api/campaigns/:id/email-stats Admin Email statistics

Responses

Prefix: /api/campaigns (public) and /api/responses (admin + actions)

Public

Method Path Auth Description
GET /api/campaigns/:slug/responses List approved public responses
GET /api/campaigns/:slug/response-stats Response statistics
POST /api/campaigns/:slug/responses Submit response (rate limited: 10/hour)
POST /api/responses/:id/upvote Optional Upvote a response
DELETE /api/responses/:id/upvote Optional Remove upvote
GET /api/responses/:id/verify/:token Verify response via email link

Admin

Auth: Admin roles

Method Path Description
GET /api/responses All responses with filters
PATCH /api/responses/:id/status Approve or reject response
POST /api/responses/:id/resend-verification Resend verification email
DELETE /api/responses/:id Delete response

Representatives

Prefix: /api/representatives

Method Path Auth Description
GET /api/representatives/by-postal/:postalCode Lookup representatives by postal code (cache-first)
GET /api/representatives/test-connection Represent API health check
GET /api/representatives/cache-stats Admin Cache statistics
GET /api/representatives Admin Paginated cached representatives
GET /api/representatives/:id Admin Single cached representative
DELETE /api/representatives/by-postal/:postalCode Admin Clear cache for postal code
DELETE /api/representatives/:id Admin Delete cached representative

Query parameters for postal code lookup:

Param Type Description
refresh boolean Force API call, bypass cache

Email Queue

Prefix: /api/email-queue · Auth: Admin roles

Method Path Description
GET /api/email-queue/stats BullMQ queue statistics (waiting, active, completed, failed)
POST /api/email-queue/pause Pause email processing
POST /api/email-queue/resume Resume email processing
POST /api/email-queue/clean Clean completed jobs

Locations

Prefix: /api/map/locations

Public

Method Path Description
GET /api/map/locations/public All geocoded locations for map (no PII); optional ?bounds=

Admin

Auth: SUPER_ADMIN or MAP_ADMIN

Method Path Description
GET /api/map/locations Paginated locations with filters
GET /api/map/locations/stats Location statistics
GET /api/map/locations/all All geocoded locations for admin map
GET /api/map/locations/export-csv CSV export
GET /api/map/locations/:id Single location
GET /api/map/locations/:id/history Edit history
POST /api/map/locations Create location
PUT /api/map/locations/:id Update location
DELETE /api/map/locations/:id Delete location
POST /api/map/locations/bulk-delete Bulk delete
POST /api/map/locations/geocode Geocode single address
POST /api/map/locations/geocode-missing Batch geocode all ungeocoded
POST /api/map/locations/reverse-geocode Reverse geocode lat/lng to address
POST /api/map/locations/import-csv Import from CSV (10 MB limit)
POST /api/map/locations/import-bulk Bulk NAR or standard CSV import (100 MB limit)

Bulk Geocode

Prefix: /api/map/locations/bulk-geocode · Auth: Map admins

Method Path Description
POST /api/map/locations/bulk-geocode Start BullMQ bulk geocoding job
GET /api/map/locations/bulk-geocode/:jobId Poll job status
GET /api/map/locations/bulk-geocode/stats Queue statistics

NAR Import

Prefix: /api/map/nar-import · Auth: Map admins

Method Path Description
GET /api/map/nar-import/datasets Available NAR datasets by province
POST /api/map/nar-import Start province import (fire-and-forget)
GET /api/map/nar-import/status/:importId Poll import progress
NAR Import body
{
  "provinceCode": "24",
  "filterType": "city",
  "filterCity": "Edmonton",
  "residentialOnly": true,
  "deduplicateRadius": 10,
  "batchSize": 500
}

Area Import

Prefix: /api/map/area-import · Auth: Map admins

Method Path Description
POST /api/map/area-import/preview Preview bounds + estimated record counts
POST /api/map/area-import Start area import (fire-and-forget)
GET /api/map/area-import/status/:importId Poll import progress

Cuts (Polygons)

Prefix: /api/map/cuts

Method Path Auth Description
GET /api/map/cuts/public All public cuts as GeoJSON
GET /api/map/cuts Map admin Paginated cuts list
GET /api/map/cuts/:id Map admin Single cut
POST /api/map/cuts Map admin Create cut (polygon GeoJSON)
PUT /api/map/cuts/:id Map admin Update cut
DELETE /api/map/cuts/:id Map admin Delete cut
GET /api/map/cuts/:id/locations Map admin All locations within cut polygon
GET /api/map/cuts/:id/statistics Map admin Support level breakdown
GET /api/map/cuts/export-geojson Map admin All cuts as GeoJSON FeatureCollection
GET /api/map/cuts/:id/export-geojson Map admin Single cut as GeoJSON Feature
POST /api/map/cuts/import-geojson Map admin Import cuts from GeoJSON file

Shifts

Prefix: /api/map/shifts

Public

Method Path Description
GET /api/map/shifts/public List upcoming public shifts
POST /api/map/shifts/public/:id/signup Public signup (creates TEMP user if needed; rate limited: 10/hour)

Volunteer

Auth: Any authenticated user

Method Path Description
GET /api/map/shifts/volunteer/upcoming Upcoming shifts with signup status
GET /api/map/shifts/volunteer/my-signups Own confirmed signups
POST /api/map/shifts/volunteer/:id/signup Sign up for shift
DELETE /api/map/shifts/volunteer/:id/signup Cancel signup

Admin

Auth: Map admins

Method Path Description
GET /api/map/shifts Paginated shifts with filters
GET /api/map/shifts/stats Statistics
GET /api/map/shifts/calendar Calendar data (?startDate=&endDate=)
GET /api/map/shifts/:id Single shift with signups
POST /api/map/shifts Create shift
PUT /api/map/shifts/:id Update shift
DELETE /api/map/shifts/:id Delete shift
POST /api/map/shifts/:id/signups Admin-add volunteer
DELETE /api/map/shifts/:id/signups/:signupId Remove volunteer
POST /api/map/shifts/:id/email-details Email details to all volunteers

Shift Series

Auth: Map admins

Method Path Description
POST /api/map/shifts/series Create recurring shift series
GET /api/map/shifts/series/:id Get series
PUT /api/map/shifts/series/:id Update series
DELETE /api/map/shifts/series/:id Delete series

Canvassing

Prefix: /api/map/canvass

Volunteer

Auth: Any authenticated user

Method Path Description
GET /api/map/canvass/my/assignments Shift assignments
GET /api/map/canvass/my/stats Personal canvass statistics
GET /api/map/canvass/my/visits Visit history
GET /api/map/canvass/my/session Active canvass session
POST /api/map/canvass/sessions Start canvass session
POST /api/map/canvass/sessions/:id/end End session
GET /api/map/canvass/cuts/:cutId/locations Locations in cut with visit annotations
GET /api/map/canvass/cuts/:cutId/route Walking route algorithm for cut
GET /api/map/canvass/locations All locations with visit annotations
PUT /api/map/canvass/locations/:id Edit address (role-gated fields)
POST /api/map/canvass/locations Create location
POST /api/map/canvass/reverse-geocode Reverse geocode lat/lng
POST /api/map/canvass/geocode-search Geocode address for map (rate limited: 10/min)
POST /api/map/canvass/visits Record door knock (rate limited: 30/min)
POST /api/map/canvass/visits/bulk Record visit for all unvisited units (rate limited: 5/min)

Admin

Auth: SUPER_ADMIN or MAP_ADMIN

Method Path Description
GET /api/map/canvass/stats Platform-wide canvass statistics
GET /api/map/canvass/stats/cuts/:cutId Statistics for specific cut
GET /api/map/canvass/activity Recent activity feed
GET /api/map/canvass/volunteers All volunteers with canvass activity
GET /api/map/canvass/volunteers/:userId Individual volunteer statistics
GET /api/map/canvass/visits All visits with filters

GPS Tracking

Prefix: /api/map/tracking

Volunteer

Auth: Any authenticated user

Method Path Description
POST /api/map/tracking/sessions Start GPS tracking session
POST /api/map/tracking/sessions/:id/end End tracking session
POST /api/map/tracking/sessions/:id/points Submit GPS point batch (rate limited: 6/min)
POST /api/map/tracking/sessions/:id/link-canvass Link to canvass session
GET /api/map/tracking/my/session Active tracking session
GET /api/map/tracking/my/sessions Own historical sessions
GET /api/map/tracking/my/sessions/:id/route Full route for own session

Admin

Auth: Map admins

Method Path Description
GET /api/map/tracking/live Live volunteer positions + trails
GET /api/map/tracking/sessions All historical tracking sessions
GET /api/map/tracking/sessions/:id/route Full route for any session

Map Settings

Prefix: /api/map/settings

Method Path Auth Description
GET /api/map/settings Public map settings (center, zoom, walk sheet config)
PUT /api/map/settings Map admin Update map settings

Geocoding

Prefix: /api/map/geocoding · Auth: Map admins

Method Path Description
GET /api/map/geocoding/search Geocode address search (?q=&limit=1-10)

Landing Pages

Prefix: /api/pages and /api/page-blocks

Public

Method Path Auth Description
GET /api/pages/:slug/view Get published page by slug

Admin

Auth: Admin roles

Method Path Description
GET /api/pages Paginated landing pages
GET /api/pages/:id Single page
POST /api/pages Create page
PUT /api/pages/:id Update page
DELETE /api/pages/:id Delete page
POST /api/pages/sync Sync MkDocs overrides from filesystem
POST /api/pages/validate Validate and repair MkDocs exports

Block Library

Auth: Admin roles

Method Path Description
GET /api/page-blocks List blocks
GET /api/page-blocks/:id Single block
POST /api/page-blocks Create block
PUT /api/page-blocks/:id Update block
DELETE /api/page-blocks/:id Delete block

Email Templates

Prefix: /api/email-templates · Auth: Admin roles (seed/cache require SUPER_ADMIN)

Method Path Description
GET /api/email-templates List templates
GET /api/email-templates/:id Single template
POST /api/email-templates Create template
PUT /api/email-templates/:id Update template
DELETE /api/email-templates/:id Delete template
GET /api/email-templates/:id/versions Version history
GET /api/email-templates/:id/versions/:versionNumber Specific version
POST /api/email-templates/:id/rollback Rollback to prior version
POST /api/email-templates/validate Validate Handlebars syntax
POST /api/email-templates/:id/test Send test email (rate limited: 10/15min)
GET /api/email-templates/:id/test-logs Test send logs
POST /api/email-templates/seed Seed templates from filesystem
POST /api/email-templates/clear-cache Clear template cache

QR Codes

Method Path Auth Description
GET /api/qr Generate QR code PNG (?text=&size=50-500)

Cached for 1 hour. Returns image/png.


Site Settings

Prefix: /api/settings

Method Path Auth Description
GET /api/settings Public site settings (SMTP credentials stripped)
GET /api/settings/admin SUPER_ADMIN Full settings including SMTP credentials
PUT /api/settings SUPER_ADMIN Update settings
POST /api/settings/email/test-connection SUPER_ADMIN Test SMTP connection
POST /api/settings/email/test-send SUPER_ADMIN Send test email

Listmonk (Newsletter Sync)

Prefix: /api/listmonk · Auth: SUPER_ADMIN

Method Path Description
GET /api/listmonk Sync status + connection check
GET /api/listmonk/stats Subscriber counts from Listmonk
POST /api/listmonk/test-connection Health check
POST /api/listmonk/sync/participants Sync campaign participants
POST /api/listmonk/sync/locations Sync locations
POST /api/listmonk/sync/users Sync users
POST /api/listmonk/sync/all Run all sync operations
POST /api/listmonk/reinitialize Reinitialize Listmonk lists
GET /api/listmonk/proxy-url Proxy port + JWT for iframe

Documentation Management

Prefix: /api/docs · Auth: Authenticated, non-TEMP (write operations require SUPER_ADMIN)

Method Path Description
GET /api/docs/status MkDocs + Code Server availability
GET /api/docs/config Port numbers for iframe URLs
GET /api/docs/mkdocs-config Read raw mkdocs.yml
PUT /api/docs/mkdocs-config Write mkdocs.yml
POST /api/docs/build Trigger MkDocs build
POST /api/docs/upload Upload asset (20 MB, whitelisted extensions)
GET /api/docs/files File tree (?force=true bypasses cache)
POST /api/docs/files/rename Rename or move file
GET /api/docs/files/* Read file content
PUT /api/docs/files/* Write file content
POST /api/docs/files/* Create file or folder
DELETE /api/docs/files/* Delete file or empty folder

Services

Prefix: /api/services · Auth: SUPER_ADMIN

Method Path Description
GET /api/services/status Health check all managed services (NocoDB, n8n, Gitea, MailHog, Mini QR, Excalidraw, Homepage)
GET /api/services/config Port numbers + subdomain info

Pangolin (Tunnel Management)

Prefix: /api/pangolin · Auth: SUPER_ADMIN

Method Path Description
GET /api/pangolin/status Tunnel health + connection info
GET /api/pangolin/config Current env configuration
GET /api/pangolin/newt-status Newt container status
POST /api/pangolin/newt-restart Restart Newt container
GET /api/pangolin/sites List Pangolin sites
GET /api/pangolin/exit-nodes Available exit nodes
GET /api/pangolin/resource-definitions Resource definitions from YAML
GET /api/pangolin/resources List resources
POST /api/pangolin/setup Create site + all resources (rate limited: ⅗min)
POST /api/pangolin/sync Sync resources (create missing, update changed)
PUT /api/pangolin/resource/:id Update resource
DELETE /api/pangolin/resource/:id Delete resource
GET /api/pangolin/resource/:id/clients Connected clients
GET /api/pangolin/certificate/:domainId/:domain Certificate info
POST /api/pangolin/certificate/:certId Update certificate

Observability

Prefix: /api/observability · Auth: SUPER_ADMIN · Rate limited: 20/min

Method Path Description
GET /api/observability/status Check 7 monitoring services
GET /api/observability/metrics-summary Key metrics from Prometheus
GET /api/observability/alerts Active alerts from Alertmanager

Payments

Prefix: /api/payments

Public

Method Path Auth Description
GET /api/payments/config Stripe publishable key + donation settings
GET /api/payments/plans Active subscription plans
GET /api/payments/products Active products (?type=)
POST /api/payments/subscribe Create subscription checkout
POST /api/payments/purchase Optional Product checkout (guest or logged-in)
POST /api/payments/donate Donation checkout
GET /api/payments/my-subscription Current subscription
POST /api/payments/my-subscription/cancel Cancel subscription
POST /api/payments/webhook Stripe webhook (raw body)

Admin

Auth: SUPER_ADMIN

Method Path Description
GET /api/payments/admin/settings Payment settings (secrets masked)
PUT /api/payments/admin/settings Update payment settings
POST /api/payments/admin/settings/test-connection Test Stripe connection
GET /api/payments/admin/dashboard Subscription + donation statistics
GET /api/payments/admin/plans All subscription plans
POST /api/payments/admin/plans Create plan
PUT /api/payments/admin/plans/:id Update plan
DELETE /api/payments/admin/plans/:id Delete plan
POST /api/payments/admin/plans/:id/sync-stripe Sync plan to Stripe
GET /api/payments/admin/subscriptions All subscriptions with filters
POST /api/payments/admin/subscriptions/:id/cancel Cancel subscription
GET /api/payments/admin/products All products
POST /api/payments/admin/products Create product
PUT /api/payments/admin/products/:id Update product
DELETE /api/payments/admin/products/:id Delete product
POST /api/payments/admin/products/:id/sync-stripe Sync product to Stripe
GET /api/payments/admin/orders List orders
POST /api/payments/admin/orders/:id/refund Refund order
GET /api/payments/admin/donations List donations
GET /api/payments/admin/export CSV export of completed orders

Media API (Fastify — Port 4100)

The Media API is a separate Fastify server sharing the same PostgreSQL database. It handles all video-related functionality.

Health

Method Path Auth Description
GET /health Media API health check

Videos (Admin)

Prefix: /api/videos · Auth: Admin roles

CRUD & Publishing

Method Path Description
GET /api/videos List videos (?limit=&offset=&search=&orientation=&producers=&isShort=)
GET /api/videos/producers Distinct producer list
GET /api/videos/health Video count health check
GET /api/videos/:id Single video detail
PATCH /api/videos/:id Update metadata (title, producer, tags, quality, etc.)
POST /api/videos/:id/publish Publish to category
POST /api/videos/:id/unpublish Unpublish
POST /api/videos/bulk-publish Bulk publish
POST /api/videos/bulk-unpublish Bulk unpublish
POST /api/videos/:id/lock Lock published video
POST /api/videos/:id/unlock Unlock video
POST /api/videos/:id/generate-thumbnail Generate thumbnail via FFmpeg
POST /api/videos/bulk-generate-thumbnails Bulk thumbnail generation

Upload

Method Path Description
POST /api/videos/upload Single video upload (multipart, 10 GB limit, streams to disk)
POST /api/videos/upload/batch Batch upload (returns 207 multi-status)

Actions

Method Path Description
POST /api/videos/:id/duplicate Duplicate video record
POST /api/videos/:id/replace Replace video file, keep metadata
GET /api/videos/:id/analytics Detailed analytics (?startDate=&endDate=)
POST /api/videos/:id/reset-analytics Reset all analytics
GET /api/videos/:id/preview-link Generate 24-hour JWT preview link
GET /api/videos/analytics/top Top videos (?metric=views|watchTime&limit=)
GET /api/videos/analytics/overview Global analytics overview

Scheduling

Method Path Description
POST /api/videos/:id/schedule-publish Schedule future publish ({publishAt, timezone?})
POST /api/videos/:id/schedule-unpublish Schedule future unpublish
DELETE /api/videos/:id/schedule/:action Cancel scheduled operation
GET /api/videos/schedules/upcoming Upcoming scheduled operations
GET /api/videos/:id/schedule-history Schedule history for video
GET /api/videos/schedules/stats Schedule queue statistics
POST /api/videos/schedules/pause Pause schedule queue
POST /api/videos/schedules/resume Resume schedule queue
POST /api/videos/schedules/cleanup Clean old completed jobs

Video Fetch

Method Path Description
POST /api/videos/fetch Submit fetch job ({urls: string[]}, 1–20 URLs)
GET /api/videos/fetch/jobs List recent fetch jobs
GET /api/videos/fetch/jobs/:jobId Job detail + log
GET /api/videos/fetch/jobs/:jobId/log SSE log stream (Redis pub/sub)
DELETE /api/videos/fetch/jobs/:jobId Cancel fetch job

Streaming (Public)

Prefix: /api/videos

Method Path Auth Description
GET /api/videos/stream/health Streaming health check
GET /api/videos/:id/stream Optional HTTP range-supporting video stream
GET /api/videos/:id/thumbnail Optional Serve thumbnail image
GET /api/videos/:id/metadata Public video metadata for embedding

Note

Admins can stream unpublished videos by providing a valid JWT.


Prefix: /api/public

Method Path Auth Description
GET /api/public Optional Published videos (?limit=&offset=&search=&sort=recent|popular|oldest&category=)
GET /api/public/categories Optional Categories with video counts
GET /api/public/producers Optional Published producers
GET /api/public/:id Optional Single published video
GET /api/public/:id/thumbnail Optional Published thumbnail
GET /api/public/:id/stream Optional Published video stream

Tracking

Prefix: /api/track · Auth: None required

Method Path Description
GET /api/track/health Tracking health check
POST /api/track/view Record video view (returns {viewId})
POST /api/track/event Record play/pause/seek/complete event
POST /api/track/heartbeat Update watch time (10s interval, sendBeacon)
POST /api/track/batch Batch up to 50 tracking events
Tracking is GDPR-compliant

IP addresses are hashed with a daily-rotating salt. Raw IPs are never stored. Tracking data is retained for 90 days.


Reactions

Prefix: /api/reactions

Method Path Auth Description
GET /api/reactions/config Available reaction types + emoji mappings
GET /api/reactions List reactions (?mediaId=&userId=&limit=)
GET /api/reactions/:mediaId/chat Reactions in chat timeline format
POST /api/reactions Add reaction (30s cooldown per type)

Available types: like, love, laugh, wow, sad, angry


Comments & Chat

Public Comments

Method Path Auth Description
GET /api/public/:id/comments List comments (?limit=&offset=)
POST /api/public/:id/comments Optional Create comment (word-filtered; rate limited: 5/min)
GET /api/public/:id/chat-stream SSE stream for real-time chat (30s keepalive)

Comment Admin

Prefix: /api/media/admin/comments · Auth: Admin roles

Method Path Description
GET /api/media/admin/comments/stats Counts by status
GET /api/media/admin/comments All comments with filters
PATCH /api/media/admin/comments/:id/approve Approve comment
PATCH /api/media/admin/comments/:id/hide Hide comment
PATCH /api/media/admin/comments/:id/unhide Unhide comment
PUT /api/media/admin/comments/:id/notes Update moderation notes
DELETE /api/media/admin/comments/:id Delete comment

Word Filters

Prefix: /api/media/admin/word-filters · Auth: Admin roles

Method Path Description
GET /api/media/admin/word-filters List filter entries grouped by level
POST /api/media/admin/word-filters Add word ({word, level: low|medium|high|custom})
DELETE /api/media/admin/word-filters/:id Remove word

Chat Threads & Notifications

Auth: Authenticated

Method Path Description
GET /api/media/chat/threads Videos with user's comments + unread counts
POST /api/media/chat/threads/:mediaId/read Mark thread as read
GET /api/media/notifications/stream Per-user SSE notification stream (?token=)

Shorts

Method Path Auth Description
GET /api/shorts Optional Shorts feed (?sort=recent|popular|random)
POST /api/shorts/scan Admin Auto-classify short videos by duration

Upvotes

Method Path Auth Description
POST /api/public/:id/upvote Toggle upvote (session-based via X-Session-ID header)
GET /api/public/:id/upvote-status Check upvote status for current session

Playlists

Public

Prefix: /api/playlists

Method Path Auth Description
GET /api/playlists/featured Optional Featured playlists
GET /api/playlists/popular Optional Popular public playlists (?search=)
GET /api/playlists/share/:token Optional Playlist by share token
GET /api/playlists/:id Optional Playlist detail (public, owner, or share token)
POST /api/playlists/:id/view Optional Record playlist view

User Playlists

Auth: Authenticated

Method Path Description
GET /api/playlists/my Own playlists
POST /api/playlists Create playlist
PUT /api/playlists/:id Update playlist (ownership check)
DELETE /api/playlists/:id Delete playlist
POST /api/playlists/:id/videos Add video ({mediaId})
DELETE /api/playlists/:id/videos/:mediaId Remove video
PUT /api/playlists/:id/videos/reorder Reorder videos
POST /api/playlists/:id/share Generate share token
DELETE /api/playlists/:id/share Revoke share token

Playlist Admin

Prefix: /api/media/playlists · Auth: Admin roles

Method Path Description
GET /api/media/playlists All playlists
GET /api/media/playlists/featured Featured playlists with admin info
POST /api/media/playlists/:id/feature Feature a playlist
DELETE /api/media/playlists/:id/feature Unfeature a playlist
PUT /api/media/playlists/featured/reorder Reorder featured playlists
PUT /api/media/playlists/:id Admin update any playlist
POST /api/media/playlists/:id/duplicate Duplicate playlist
DELETE /api/media/playlists/:id Admin delete any playlist

User Profile

Prefix: /api/media/me · Auth: Authenticated

Method Path Description
GET /api/media/me/stats User stats + 30-day activity + achievements
GET /api/media/me/watch-history Paginated watch history
POST /api/media/me/stats/recalculate Recompute stats from raw data
GET /api/media/me/settings Privacy settings
PUT /api/media/me/settings Update privacy settings
PUT /api/media/me/profile Update display name
PUT /api/media/me/password Change password

Route Summary

API Module Endpoint Count
Express Auth 9
Users 7
Dashboard 7
Campaigns (CRUD + public + user + moderation + emails) 16
Responses 10
Email Queue 4
Representatives 7
Locations (CRUD + geocode + import) 21
Cuts 11
Shifts (CRUD + series) 19
Canvassing 20
GPS Tracking 10
Map Settings + Geocoding 3
Pages + Blocks 12
Email Templates 13
QR Codes 1
Site Settings 5
Listmonk 9
Docs Management 11
Services 2
Pangolin 16
Observability 3
Payments (public + admin) 29
Health + Metrics 3
Express Total ~248
Fastify Videos (CRUD + upload + actions + schedule + fetch) 39
Streaming 4
Public Gallery 6
Tracking 5
Reactions 4
Comments + Chat 13
Shorts + Upvotes 4
Playlists (public + user + admin) 18
User Profile 7
Health 1
Fastify Total ~101
Grand Total ~349