Skip to main content

API Authentication Enforcement

Every API endpoint follows a strict authentication and authorization pattern.

Auth Matrix

EndpointAuth LevelToken CostNotes
GET /api/track-pixelNoneNonePublic tracking pixel (hashed email, salted IP hash)
POST /api/track-amp-eventNoneNonePublic AMP interaction tracking
GET /api/view-emailNoneNonePublic "View in Browser" page
GET /api/blog-ogNoneNonePublic OG image
GET /api/rag-statsNoneNonePublic knowledge base stats (/how-it-works)
POST /api/generateUserai_generationMain RAG pipeline
POST /api/generate-emailUserai_generationSimple generation
POST /api/gen/copy / gen/blueprint / gen/continuityUserNoneStaged generation pipeline
POST /api/send-email-mailgunUserNoneMailgun delivery; sender = verified account email
POST /api/validate-ampNoneNoneAMP validation (stateless validator)
POST /api/unsubscribeSession or HMAC tokenNoneSigned token via UNSUB_TOKEN_SECRET
POST /api/mailgun-webhookHMAC signatureNoneMAILGUN_WEBHOOK_SIGNING_KEY required
POST /api/notify-signupShared secretNoneSupabase webhook, SIGNUP_WEBHOOK_SECRET
POST /api/eval/judgeAdminNoneEval harness LLM judge
POST /api/deploy-emailAdminNoneEmail deployment
/api/admin/*AdminNoneRAG management, eval storage, auto-tagging

Enforcement Pattern

Every protected endpoint follows this pattern at the top of the handler:

export default async function handler(req, res) {
// 1. Method check
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}

// 2. Auth verification
const user = await verifyUser(req, res);
if (!user) return; // 401 already sent

// 3. Token spending (if applicable)
const tokenResult = await spendTokensServer(req, res, 'ai_generation');
if (!tokenResult) return; // 402 already sent

// 4. Input validation
const { prompt } = req.body;
if (!prompt) {
return res.status(400).json({ error: 'Prompt is required' });
}

// 5. Business logic...
}

Auth Module

A single shared module, api/_auth.ts, provides verifyUser, verifyAdmin, spendTokensServer, and setCorsHeaders. All routes — TypeScript and JavaScript alike (generate.js, api/admin/*.js, api/gen/*.js, api/eval/*.js) — import from it using the .js extension, which the ESM api/ runtime requires.

Token Spending Security

Token deduction is server-side only. The flow:

  1. Frontend calls checkCanAfford() — read-only, no deduction
  2. Frontend executes the API call if affordable
  3. Server calls spendTokensServer() — atomic deduction via spend_tokens RPC
  4. Frontend calls refreshBalance() to sync UI

This ensures users cannot bypass token costs by calling APIs directly (e.g., via curl).