Ask AI API Server

March 24, 2026 · View on GitHub

Backend API for the Ask AI widget on the Multipaz developer website. Provides chat (Gemini), text-to-speech (ElevenLabs), and feedback collection (Google Sheets) endpoints.

Environment Variables

VariableRequiredDescription
GEMINI_API_KEYYesGoogle Gemini API key for the chat endpoint
ELEVENLABS_API_KEYNoElevenLabs API key for text-to-speech
ELEVENLABS_VOICE_IDNoElevenLabs voice ID (default: JBFqnCBsd6RMkjVDRZzb — George)
ELEVENLABS_MODEL_IDNoElevenLabs model (default: eleven_turbo_v2_5)
FEEDBACK_WEBHOOK_URLNoGoogle Apps Script web app URL for feedback collection
ALLOWED_ORIGINSNoComma-separated allowed CORS origins (default: http://localhost:3000,http://localhost:3001,http://localhost:3010)
RATE_LIMIT_PER_MINNoMax requests per IP per minute (default: 10)
DAILY_REQUEST_LIMITNoGlobal daily request cap (default: 300)
PORTNoServer port (default: 3010)

For production, these are set as Vercel environment variables (Settings > Environment Variables in the Vercel dashboard, or via vercel env add).

The Docusaurus frontend also requires ASK_AI_API_URL set as a GitHub Actions variable (repo Settings > Secrets and variables > Actions > Variables) since it's baked in at build time.

Running Locally

# Install dependencies
cd api && npm install

# Start the server (minimum — chat only)
GEMINI_API_KEY=your_key node server.js

# Start with all features
GEMINI_API_KEY=your_key \
ELEVENLABS_API_KEY=your_key \
FEEDBACK_WEBHOOK_URL=https://script.google.com/macros/s/.../exec \
node server.js

Endpoints

POST /api/chat

Streaming chat powered by Gemini. Accepts { messages: [{ role, content }] } and returns Server-Sent Events.

POST /api/tts

Text-to-speech via ElevenLabs. Accepts { text: string } and returns audio/mpeg stream.

POST /api/feedback

Feedback proxy — forwards thumbs-up/down ratings to a Google Sheets webhook. Accepts { rating: "up"|"down", question: string, answer: string }.

Setting Up Feedback (Google Sheets)

  1. Create a Google Sheet with columns: timestamp, rating, question, answer
  2. Open Extensions > Apps Script
  3. Paste the following:
function doPost(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var data = JSON.parse(e.postData.contents);
  sheet.appendRow([
    data.timestamp,
    data.rating,
    data.question,
    data.answer
  ]);
  return ContentService.createTextOutput('OK');
}
  1. Deploy > New deployment > Type: Web app > Execute as: Me > Who has access: Anyone
  2. Authorize when prompted
  3. Copy the web app URL and set it as FEEDBACK_WEBHOOK_URL

Privacy

Feedback collection is anonymous. The only data stored is:

  • Timestamp
  • Rating (up/down)
  • The question and answer text

No personally identifiable information is collected — no IP addresses, user identities, cookies, or tracking IDs.