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
andALLOWED_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), optionalAuthorization: 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
(defaultclip-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) inALLOWED_ORIGINS
. For Electron, setALLOW_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.