Skip to content

Commit dac90f5

Browse files
sahilsuman933cursoragentsahil
authored
Add proxy server guide documentation to security section (#638)
Co-authored-by: Cursor Agent <[email protected]> Co-authored-by: sahil <[email protected]>
1 parent 84361eb commit dac90f5

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed

fern/docs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ navigation:
603603
path: security-and-privacy/hipaa.mdx
604604
- page: PCI compliance
605605
path: security-and-privacy/PCI.mdx
606+
- page: Proxy server guide
607+
path: security-and-privacy/proxy-server.mdx
606608
- link: SOC-2 Compliance
607609
href: https://security.vapi.ai/
608610
- section: Legal
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
---
2+
title: Proxy server guide
3+
subtitle: Keep assistant configs and API keys on your backend. Route Web SDK calls through your proxy.
4+
slug: security-and-privacy/proxy-server
5+
---
6+
7+
## Overview
8+
9+
Proxy server keeps assistant configs and API keys on your backend. Frontend sends custom data, backend maps to Vapi calls.
10+
11+
**Flow**: Frontend -> Your Proxy -> Vapi API -> Response -> Frontend
12+
13+
<Warning>Never expose your private API key in the browser. Keep it on your server and read it from environment variables.</Warning>
14+
15+
<Info>For public web clients, consider using <a href="/customization/jwt-authentication">JWT authentication</a> to further restrict client capabilities.</Info>
16+
17+
## Frontend setup
18+
19+
```javascript title="frontend.js"
20+
import Vapi from '@vapi-ai/web';
21+
22+
const vapi = new Vapi('your-token', 'https://your-proxy.com');
23+
// Second parameter is your backend/proxy service URL. Without this, calls route to Vapi API directly.
24+
25+
vapi.start({
26+
userId: 'customer123',
27+
assistantType: 'sales-coach',
28+
// Send any custom data your backend needs
29+
});
30+
```
31+
32+
<Note>
33+
The frontend passes only non-sensitive context (e.g., userId, assistant type). Your backend selects the actual assistant configuration and authenticates to Vapi.
34+
</Note>
35+
36+
## Backend proxy server (example)
37+
38+
```javascript title="cloudflare-worker.js" wordWrap
39+
export default {
40+
async fetch(request, env, ctx) {
41+
const url = new URL(request.url);
42+
43+
// Basic CORS support (adjust origins/headers to your needs)
44+
const corsHeaders = {
45+
'Access-Control-Allow-Origin': '*',
46+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
47+
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
48+
};
49+
50+
if (request.method === 'OPTIONS') {
51+
return new Response(null, { status: 204, headers: corsHeaders });
52+
}
53+
54+
// Handle Vapi API calls
55+
if (url.pathname.startsWith('/call')) {
56+
try {
57+
const { userId, assistantType, ...rest } = await request.json();
58+
const assistantConfig = getAssistantConfig(userId, assistantType, rest);
59+
60+
const response = await fetch(`https://api.vapi.ai${url.pathname}`, {
61+
method: 'POST',
62+
headers: {
63+
Authorization: `Bearer ${env.VAPI_API_KEY}`,
64+
'Content-Type': 'application/json',
65+
},
66+
body: JSON.stringify(assistantConfig),
67+
});
68+
69+
return new Response(response.body, {
70+
status: response.status,
71+
headers: { 'Content-Type': 'application/json', ...corsHeaders },
72+
});
73+
} catch (error) {
74+
return new Response(JSON.stringify({ error: 'Proxy error', details: String(error) }), {
75+
status: 500,
76+
headers: { 'Content-Type': 'application/json', ...corsHeaders },
77+
});
78+
}
79+
}
80+
81+
return new Response('Proxy running', { headers: corsHeaders });
82+
},
83+
};
84+
85+
function getAssistantConfig(userId, assistantType) {
86+
if (assistantType === 'existing') {
87+
return { assistantId: 'YOUR_ASSISTANT_ID' };
88+
}
89+
90+
return {
91+
assistant: {
92+
// Your transient assistant config here
93+
},
94+
};
95+
}
96+
```
97+
98+
<Steps>
99+
<Step title="Extract custom data from the request">
100+
Parse and validate the fields your frontend sends (e.g., <code>userId</code>, <code>assistantType</code>), plus any other context you need.
101+
</Step>
102+
<Step title="Map to assistant configuration">
103+
Choose a permanent assistant ID or build a transient assistant configuration based on the request.
104+
</Step>
105+
<Step title="Call Vapi and return the response">
106+
Authenticate to Vapi with your server-side API key and stream/forward the response to the client.
107+
</Step>
108+
</Steps>
109+
110+
<Check>Result: Secure calls with configs and secrets hidden on your backend.</Check>
111+
112+
### Related
113+
114+
- <a href="/customization/jwt-authentication">JWT authentication</a>
115+
- <a href="/server-url">Server URLs</a>

0 commit comments

Comments
 (0)