Backend routes

This app includes server routes for stock media, AI, transcription, emoji catalogs, and admin tools. Routes are guarded by strict origin validation, rate limits, and security headers. This page documents the available endpoints, required environment variables, and common errors (like 403 Unauthorized origin).

Security model

  • Origin validation: Production requests must come from an allowed origin (configured via NEXT_PUBLIC_SITE_URL and ALLOWED_ORIGINS).
  • CORS: Middleware sets Access-Control-Allow-* headers for allowed origins and handles OPTIONS preflight.
  • Rate limits: Global middleware caps API at ~30 req/min per IP; some routes add stricter per‑route caps.
  • Secrets: API keys/tokens are server‑side only (no NEXT_PUBLIC_ prefix).
  • Headers: CSP, Permissions‑Policy, and COOP/COEP are applied to enable safe WASM and capture APIs.

403 “Unauthorized origin” means your request’s Origin/Referer did not match the configured list. For Electron/file://contexts, set ALLOW_NULL_ORIGIN=true only if you trust the shell.

Environment variables

# Site and CORS
NEXT_PUBLIC_SITE_URL=https://your.app
ALLOWED_ORIGINS=https://your.app,https://www.your.app
ALLOW_NULL_ORIGIN=false

# Stock media providers
PEXELS_API_KEY=...            # /api/pexels/*
TENOR_API_KEY=...             # /api/tenor/search
TENOR_CLIENT_KEY=clip-js
MEME_API_KEY=...              # /api/meme/*

# AI/Transcription
OPENAI_API_KEY=...            # /api/ai (if ALLOW_SERVER_KEY=true)
AI_REQUIRE_CLIENT_KEY=true     # Require client-provided OpenAI key by default
AI_ALLOW_SERVER_KEY=false      # Set true to use server key instead
AI_ALLOW_CLIENT_KEYS=false     # Set true + allowlist to accept client keys
AI_ALLOWED_CLIENT_KEY_HASHES=  # Comma-separated list from hashAPIKey()
AI_ROUTE_BEARER_TOKEN=        # Optional bearer for /api/ai

TRANSCRIPTION_BEARER_TOKEN=...    # /api/transcription worker token (hex)
TRANSCRIPTION_WORKER_URL=https://<worker>.workers.dev

AI: /api/ai

  • POST — proxy to OpenAI with origin/rate‑limit enforcement and optional route bearer.
  • Keys: can require client keys, allow a server key, or allowlist certain client keys.
  • Body: { messages: ChatMessage[], model?: string, maxTokens?: number, temperature?: number, apiKey?: string }.
  • Headers: x-openai-key (alternative to body.apiKey), optional Authorization: Bearer <AI_ROUTE_BEARER_TOKEN>.
  • Errors: 401 invalid key, 403 origin, 429 rate limit, 503 not configured, mapped OpenAI upstream errors.
curl -X POST https://your.app/api/ai  -H 'Content-Type: application/json'  -H 'x-openai-key: sk-... (if client keys allowed)'  -d '{"model":"gpt-5-mini","messages":[{"role":"user","content":"Hello"}]}'

Transcription: /api/transcription

  • POST — forwards audio/video to your Cloudflare Whisper Worker (configurable URL) using a server bearer token.
  • FormData fields: audio (WAV/WEBM/MP3/MP4), task (transcribe|translate), language, vad_filter.
  • GET — health probe; indicates whether the route is configured.
  • Errors: 400 invalid/missing file, 401/403 auth/origin, 429 route rate limit, 503 misconfiguration.
curl -X POST https://your.app/api/transcription  -H 'Authorization: Bearer <server-token-if-required-by-worker>'  -F 'audio=@sample.wav' -F 'task=transcribe' -F 'language=en' -F 'vad_filter=true'

Stock media: Pexels

  • GET /api/pexels/images — search/curated images; Edge runtime; retries with backoff.
  • GET /api/pexels/videos — search/popular videos; Edge runtime; retries with backoff.
  • GET/POST /api/pexels-proxy — fetch/stream media from allowed Pexels/Vimeo hosts; validates URL and forwards Range headers.
  • Env: PEXELS_API_KEY.

Stock media: Tenor

  • GET /api/tenor/search — GIFs/Stickers; returns lightweight objects for grid/preview; Edge runtime; rate‑limited and retried.
  • GET /api/tenor/proxy?url=... — proxied media with strict host allowlist and HTTPS enforcement.
  • Env: TENOR_API_KEY, TENOR_CLIENT_KEY (default clip-js).

Meme API

  • GET /api/meme/videos?action=all|search|random&q=... — returns meme video items.
  • GET /api/meme/sounds?action=all|search|random&q=... — returns meme sound items.
  • Security: Validates origin + per‑IP rate limit (60/min). Env: MEME_API_KEY.

Emoji and catalogs

  • GET /api/animated-emojis — list of bundled animated emoji packs.
  • GET /api/emoji/local-list — local emoji index for search/autocomplete.
  • GET /api/emoji/maps, /api/emoji/semantic-index — specialized emoji datasets for UI features.

Admin and diagnostics

  • GET /api/health — shows configuration/health for AI/transcription and simple route stats.
  • Admin: /api/admin/* endpoints (auth, videos, articles) used by the internal dashboard. Protected via middleware auth.

Common errors and fixes

  • 403 Unauthorized origin: Set NEXT_PUBLIC_SITE_URL and include the public URL(s) in ALLOWED_ORIGINS. For Electron, set ALLOW_NULL_ORIGIN=true.
  • 429 Rate limit exceeded: Reduce request rate or test locally; global and per‑route limits are applied.
  • 500 “API key not configured”: Provide the required key (Pexels, Tenor, Meme, OpenAI, or Transcription token) in server env.
  • Tenor media blocked: Media must be fetched via /api/tenor/proxy or direct if CSP allows the host.