For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
WebsiteStatusSupportDashboard
DocumentationAPI ReferenceMCPSDKsCLI (new)What's New?
DocumentationAPI ReferenceMCPSDKsCLI (new)What's New?
  • Get started
    • Introduction
    • Phone calls
    • Web calls
    • Vapi Guides
    • Composer
    • CLI quickstart
  • Assistants
    • Quickstart
    • Tools
    • Custom keywords
    • Custom voices
    • Custom transcriber
    • Custom TTS
  • Observability
    • Boards
  • Squads
    • Quickstart
    • Overview
    • Handoff tool
    • Passing data between assistants
  • Best practices
    • Prompting guide
    • Debugging voice agents
    • Enterprise environments (DEV/UAT/PROD)
    • IVR navigation
  • Phone numbers
    • Free Vapi number
    • Inbound SMS
    • Phone Number Hooks
  • Calls
    • Call end reasons
    • Troubleshoot call errors
  • Outbound Campaigns
    • Quickstart
    • Overview
  • Chat
    • Quickstart
    • Streaming
    • Non-streaming
    • OpenAI compatibility
    • Session management
    • Variable substitution
    • SMS chat
    • Web widget
    • Webhooks
  • Workflows
    • Quickstart
    • Overview
      • FAQ
      • Support
        • Data flow
        • JWT authentication
        • Recording consent plan
        • GDPR compliance
        • HIPAA compliance
        • Retrieve call artifacts
        • PCI compliance
        • Proxy server guide
        • Static IP addresses
        • SOC-2 Compliance
LogoLogo
WebsiteStatusSupportDashboard
On this page
  • Overview
  • Frontend setup
  • Backend proxy server (example)
  • Related
ResourcesSecurity and privacy

Proxy server guide

Keep assistant configs and API keys on your backend. Route Web SDK calls through your proxy.
Was this page helpful?
Edit this page
Previous

Static IP addresses

Whitelist Vapi IP addresses
Next
Built with

Overview

Proxy server keeps assistant configs and API keys on your backend. Frontend sends custom data, backend maps to Vapi calls.

Flow: Frontend -> Your Proxy -> Vapi API -> Response -> Frontend

Never expose your private API key in the browser. Keep it on your server and read it from environment variables.
For public web clients, consider using JWT authentication to further restrict client capabilities.

Frontend setup

frontend.js
1import Vapi from '@vapi-ai/web';
2
3const vapi = new Vapi('your-token', 'https://your-proxy.com');
4// Second parameter is your backend/proxy service URL. Without this, calls route to Vapi API directly.
5
6vapi.start({
7 userId: 'customer123',
8 assistantType: 'sales-coach',
9 // Send any custom data your backend needs
10});

The frontend passes only non-sensitive context (e.g., userId, assistant type). Your backend selects the actual assistant configuration and authenticates to Vapi.

Backend proxy server (example)

cloudflare-worker.js
1export default {
2 async fetch(request, env, ctx) {
3 const url = new URL(request.url);
4
5 // Basic CORS support (adjust origins/headers to your needs)
6 const corsHeaders = {
7 'Access-Control-Allow-Origin': '*',
8 'Access-Control-Allow-Methods': 'POST, OPTIONS',
9 'Access-Control-Allow-Headers': 'Content-Type, Authorization'
10 };
11
12 if (request.method === 'OPTIONS') {
13 return new Response(null, { status: 204, headers: corsHeaders });
14 }
15
16 // Handle Vapi API calls
17 if (url.pathname.startsWith('/call')) {
18 try {
19 const { userId, assistantType, ...rest } = await request.json();
20 const assistantConfig = getAssistantConfig(userId, assistantType, rest);
21
22 const response = await fetch(`https://api.vapi.ai${url.pathname}`, {
23 method: 'POST',
24 headers: {
25 Authorization: `Bearer ${env.VAPI_API_KEY}`,
26 'Content-Type': 'application/json',
27 },
28 body: JSON.stringify(assistantConfig),
29 });
30
31 return new Response(response.body, {
32 status: response.status,
33 headers: { 'Content-Type': 'application/json', ...corsHeaders },
34 });
35 } catch (error) {
36 return new Response(JSON.stringify({ error: 'Proxy error', details: String(error) }), {
37 status: 500,
38 headers: { 'Content-Type': 'application/json', ...corsHeaders },
39 });
40 }
41 }
42
43 return new Response('Proxy running', { headers: corsHeaders });
44 },
45};
46
47function getAssistantConfig(userId, assistantType) {
48 if (assistantType === 'existing') {
49 return { assistantId: 'YOUR_ASSISTANT_ID' };
50 }
51
52 return {
53 assistant: {
54 // Your transient assistant config here
55 },
56 };
57}
1

Extract custom data from the request

Parse and validate the fields your frontend sends (e.g., userId, assistantType), plus any other context you need.

2

Map to assistant configuration

Choose a permanent assistant ID or build a transient assistant configuration based on the request.

3

Call Vapi and return the response

Authenticate to Vapi with your server-side API key and stream/forward the response to the client.

Result: Secure calls with configs and secrets hidden on your backend.

Related

  • JWT authentication
  • Server URLs