Building voice AI agents with Vapi from containers, serverless, or cloud platforms? Every redeploy shifts the outbound IP you call from, which breaks IP-restricted Vapi keys and sub-600ms live calls. Route that outbound traffic through one dedicated static EU IP, and give your Vapi setup and Server URL a fixed, whitelistable address.
import requests
# Outbound leg -> routed via static EU IP
# HTTPS_PROXY=https://user:pass@eu-01.outboundgateway.com:8443
resp = requests.post(
"https://api.vapi.ai/call/phone",
headers={"Authorization": "Bearer KEY"},
json={"assistantId": "asst_1",
"customer": {"number": "+49..."}}
)
Most API pages worry about a failed request. With Vapi you're on a live phone call, and the traffic flows both ways.
Production teams lock their Vapi API key to a set of source IPs. The moment a pod, container, or Lambda moves to a new address, requests to api.vapi.ai come back unauthorized. Because call creation runs through that same key, no new calls go out.
Vapi targets sub-600ms turn-taking. Unlike a translation or image job that you retry, a dropped connection mid-conversation means a customer is left hanging in silence while your service scales up. The damage is real-time and visible to the caller.
When the assistant needs to act (book a slot, check an order), Vapi posts a function-call request to your Server URL and waits for the answer before it speaks. An unstable identity on either leg turns a smooth booking flow into awkward, broken pauses.
You whitelist your egress so Vapi trusts your key, and Vapi's Server URL calls your server (secured with a Custom Credentials token). Teams juggle both sides per environment (dev, staging, prod), each with its own shifting IPs. That's hard to audit and easy to get wrong.
"Our callers are live. We can't have the bot's line drop because something scaled up overnight."
You need the outbound identity to be a fixed address, the same one call after call, deploy after deploy.
Your voice service
HTTPS Proxy
(Static EU IP)
Vapi API
From Vapi's side, your calls always originate from the same pair of EU addresses, whether you're placing a call, updating the assistant mid-conversation, or polling call status. Two IPs, with one taking over if the other is down.
/call/phone, web calls, assistants, phone numbers, and any endpoint you reach at api.vapi.ai.
HTTPS_PROXY once and your existing HTTP client picks it up, with no call-control rewrite.
requests, fetch, and anything that honours the standard proxy environment variables.
Shipping phone and web voice agents who need the API key to keep working through every container restart and autoscale event.
Running AI phone lines where a dropped bot mid-call is customer-visible. They want an egress that doesn't change when traffic spikes.
Dialing prospects with Vapi across regions, who need one whitelistable address rather than a fleet of rotating ones.
Accountable for call audio and transcripts under GDPR, who need a documented, stable egress rather than a moving target.
Set HTTPS_PROXY and your outbound calls to Vapi leave through your fixed EU IP. No rewrite to your call logic.
Drop HTTPS_PROXY into your environment and requests honours it automatically, so the Create Call request below already leaves through your static IP.
# .env or shell
HTTPS_PROXY=https://user:pass@eu-01.outboundgateway.com:8443
VAPI_API_KEY=your_api_key
import os
import requests
# requests reads HTTPS_PROXY from the environment automatically
resp = requests.post(
"https://api.vapi.ai/call/phone",
headers={"Authorization": f"Bearer {os.environ['VAPI_API_KEY']}"},
json={
"assistantId": "asst_support_1",
"customer": {"number": "+491701234567"},
"phoneNumberId": "phn_1234",
},
)
print(resp.json()["id"]) # the call id
In Node, wire the proxy explicitly with https-proxy-agent so every fetch to api.vapi.ai goes out through your static IP.
// .env or shell
HTTPS_PROXY=https://user:pass@eu-01.outboundgateway.com:8443
VAPI_API_KEY=your_api_key
const { HttpsProxyAgent } = require('https-proxy-agent');
const agent = new HttpsProxyAgent(process.env.HTTPS_PROXY);
// This POST leaves through your static EU IP
const res = await fetch('https://api.vapi.ai/call/phone', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.VAPI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
assistantId: 'asst_support_1',
customer: { number: '+491701234567' },
}),
agent,
});
console.log(await res.json());
A note on the Server URL direction
The proxy here is for your outbound calls to api.vapi.ai, placing and controlling calls. Vapi's Server URL runs the other way: Vapi posts live conversation events and function-call requests to your server, where you secure it with a Custom Credentials token. That inbound webhook isn't something a forward proxy affects; it just needs your server to be reachable and to answer quickly enough to keep the conversation moving.
Set the variable in your platform config, the same approach in every environment. Never paste the proxy string in plaintext.
# Docker Compose: load a .env file
services:
app:
env_file:
- .env
# Kubernetes: pull it from a Secret
env:
- name: HTTPS_PROXY
valueFrom:
secretKeyRef:
name: outboundgateway-proxy
key: proxy-url
# AWS Lambda: function environment variables
HTTPS_PROXY=${OUTBOUNDGATEWAY_PROXY_URL}
Two IPs, so a call doesn't depend on one box
Your account comes with two static IP addresses (for instance 51.xx.xx.10 and 51.xx.xx.11). Register both against your Vapi key. If one proxy node is briefly unavailable, traffic shifts to the other without interrupting active work. For something as time-sensitive as a live call, that redundancy is the point.
📖 Want the longer version? Worked examples, error handling, and other languages are in the Python SSL Proxy Guide, Node.js Guide, and the rest of the docs.
Voice traffic is sensitive: audio, transcripts, phone numbers. Keeping the outbound path inside the EU matches how most EU teams want to run it.
The proxy runs in EU data centres, so your outbound call-control traffic to Vapi stays within European borders, the kind of residency detail that matters when call audio and transcripts are involved.
Because TLS passes straight through, the proxy never decodes your bearer token, the customer's phone number, or anything in the request body. It routes bytes; it doesn't read them.
Traffic doesn't bounce through US infrastructure on its way to Vapi, which removes a common complication from GDPR data-transfer reviews.
When a DPO asks "where do our call-control requests originate from?", the answer is two fixed EU addresses, not a list that changes every release. Maintenance windows are covered by the failover pair.
Two addresses to register against your key, with automatic failover, so your call traffic doesn't ride on a single point of failure.
Set the proxy variable and your existing client (requests, fetch, axios, the Vapi SDK) starts routing through it. The assistant config is untouched.
European data centres and a GDPR-conscious setup, so the outbound side of your voice stack lines up with how your compliance team wants data handled.
Phone calls, web calls, assistants, numbers, files: anything you hit at api.vapi.ai goes out through the same stable pair.
TLS passthrough means the proxy can't read your traffic. Phone numbers, call payloads, and tokens stay private the whole way.
Starting from €29/month. Flexible plans for every scale. Cancel anytime.
Stop letting pod restarts and autoscaling decide which IP your live calls come from. Put the outbound half of Vapi behind one stable, GDPR-conscious address.
€29/month starter plan • 7-day refund policy • Direct founder support
No, and that's a common point of confusion. The proxy covers your outbound calls to api.vapi.ai, like placing a call or updating an assistant mid-conversation. The Server URL runs the opposite way: Vapi posts live conversation events and function-call requests to your server, which you secure with a Custom Credentials token. That's an inbound webhook to your own endpoint, so a forward proxy doesn't touch it. You just need your server reachable and fast enough to keep the dialogue moving.
Yes, that's the main reason teams add the proxy. Vapi lets you restrict an API key to a set of source IPs, but containers, pods, and functions get a new address on every redeploy, which would normally break that restriction. By routing outbound calls through a fixed pair of EU addresses and registering both against the key, the key keeps authorising requests no matter how often your deployment restarts.
Your account gets two static IPs, and you whitelist both in Vapi. If one proxy node is briefly unavailable, outbound traffic shifts to the other automatically. Because a voice call is time-sensitive and a dropped connection is visible to the caller in real time, having the second address means a single proxy blip doesn't translate into a dead line.
Happy to talk through how a two-IP egress fits your specific Vapi setup, assistants, Server URL, and all.
Contact Our Founders →