Static IPs for Platforms That Can't Set an HTTP Proxy (Zoho Deluge, Bubble, Zapier)
Platforms that can make outbound HTTP calls but cannot set an HTTP proxy, like Zoho Deluge, Bubble, and Zapier, still get two static outbound IP addresses by calling a small relay function you host. The relay forwards each request through QuotaGuard, so the target API sees your two static IPs instead of the platform’s rotating cloud IPs. You deploy the relay once on AWS Lambda or a Google Cloud Function, point your platform at its URL, and allowlist both static IPs with the target API.
No-Proxy Platforms Get a Static IP Through a Relay Function
If your platform can call a URL but cannot set HTTP_PROXY or run a sidecar, a relay function is how you get a static outbound IP. Zoho Deluge, Bubble, and Zapier’s no-code actions all make outbound HTTP calls without a way to set a proxy, and none of them let you run QGTunnel alongside your code. So the usual approach of setting a single proxy environment variable does not apply. Their requests leave from the vendor’s shared, rotating cloud IP ranges, which any API that enforces IP allowlisting will reject. The relay solves this: it is a small function you control that does set the proxy, egresses through QuotaGuard, and hands the response back to your platform.
This pattern applies whenever the platform is a managed or no-code runtime you cannot configure at the network layer:
- Zoho Deluge (Zoho One, Zoho CRM, Zoho Creator, Zoho Flow custom functions).
invokeUrlcannot set a proxy. - Bubble.io (the API Connector and backend workflows).
- Zapier (Webhooks by Zapier and built-in app actions). A Python Code by Zapier step can set a proxy on its own HTTP client, so that one path does not need the relay.
- Similar sandboxed or serverless platforms where you cannot set proxy environment variables or run a sidecar.
The destinations that force the issue are the ones that enforce a customer-controlled IP allowlist:
- Payment gateways and banking or fintech APIs.
- Partner, EDI, and B2B APIs that gate access by source IP.
- Healthcare and other regulated-data APIs.
- Legacy or on-prem systems reachable only through a firewall allowlist.
The Relay Pattern Routes Your Request Through QuotaGuard
The relay is a forwarding function. Your platform calls it, it calls the target through QuotaGuard, and the response comes back the same way:
Your platform → relay function URL → QuotaGuard proxy → target API
Your platform sends its request to the relay’s URL with two extra headers. X-Relay-Key is a secret you generate that authorizes the call. X-Target-URL is the full URL of the API you actually want to reach. The relay checks the key, then forwards the request through QuotaGuard’s proxy to the target. The method, body, Content-Type, and Authorization headers pass through as-is, and the target’s response comes back as the relay’s response.
The relay host’s own outbound IP does not matter and is never allowlisted. Only QuotaGuard’s two static IPs reach the target, because the relay forwards through the QuotaGuard proxy. That is the whole point: the target API sees a fixed pair of IPs no matter how often your platform or the relay host recycles its addresses.
The relay’s function URL is public, so the X-Relay-Key check is what protects it. Anyone with the URL and the key can send traffic through your proxy, so treat the key like a password.
Getting Started
After creating a QuotaGuard account, you are redirected to your dashboard, where you find your Connection URL and your two static IP addresses.
Choose the right proxy region: Select the QuotaGuard region closest to the target API to minimize latency, and deploy the relay in the matching cloud region. The region is set at sign-up. Changes after sign-up require contacting support.
Your Connection URL is the value you will set as QUOTAGUARDSTATIC_URL on the relay. It looks like this, with the region host taken from your dashboard:
http://username:password@us-east-static-01.quotaguard.com:9293
Deploy the Relay on AWS Lambda in Four Steps
The published example runs on the Lambda Python runtime and uses only libraries already present there, so there is nothing to package or install. The full example lives at quotaguard/static-examples.
- In the AWS console, create a Lambda function with the Python 3.12 runtime and paste in the
lambda_function.pybelow. - Under Configuration > Environment variables, add two:
QUOTAGUARDSTATIC_URL: your Connection URL from the QuotaGuard dashboard.RELAY_KEY: a long random string you generate. This is the password for your relay. Keep it secret.
- Under Configuration > General configuration, set the timeout to 30 seconds. The 3-second default is tight for API calls.
- Under Configuration > Function URL, create a function URL with auth type NONE. The
RELAY_KEYcheck in the code is what protects it.
The function itself:
import os, base64
import urllib3
from urllib.parse import urlparse, unquote
# urllib3 does not send credentials embedded in the proxy URL,
# so split them out and pass explicit Proxy-Authorization headers.
qg = urlparse(os.environ["QUOTAGUARDSTATIC_URL"])
proxy = urllib3.ProxyManager(
f"http://{qg.hostname}:{qg.port}",
proxy_headers=urllib3.make_headers(
proxy_basic_auth=f"{unquote(qg.username)}:{unquote(qg.password)}"
),
)
def lambda_handler(event, context):
headers = event.get("headers") or {}
# Reject calls that don't carry your secret key
if headers.get("x-relay-key") != os.environ["RELAY_KEY"]:
return {"statusCode": 403, "body": "Forbidden"}
target = headers.get("x-target-url")
if not target:
return {"statusCode": 400, "body": "Missing X-Target-URL header"}
method = event.get("requestContext", {}).get("http", {}).get("method", "GET")
body = event.get("body")
if body and event.get("isBase64Encoded"):
body = base64.b64decode(body)
# Pass through the headers the target API needs
fwd = {}
for name in ("content-type", "authorization"):
if name in headers:
fwd[name] = headers[name]
resp = proxy.request(method, target, body=body, headers=fwd, timeout=30.0)
return {
"statusCode": resp.status,
"headers": {"Content-Type": resp.headers.get("Content-Type", "application/json")},
"body": resp.data.decode("utf-8", errors="replace"),
}
The function URL that AWS gives you is what your platform calls. It looks like https://<your-function-url>.lambda-url.<region>.on.aws/.
Deploy the Relay on a Google Cloud Function Using the Same Handler
The relay runs just as well as a Google Cloud Function, using the same three inputs and the same header contract. Set the same QUOTAGUARDSTATIC_URL and RELAY_KEY environment variables, build the same urllib3.ProxyManager from QUOTAGUARDSTATIC_URL, check X-Relay-Key, read X-Target-URL, and forward the request through the proxy.
The only real difference is the function signature. A Cloud Function built on the functions framework hands you a Flask request object and expects you to return a (body, status, headers) tuple, rather than Lambda’s event dict and {"statusCode", "headers", "body"} return shape. The forwarding logic in the middle is identical.
For the QuotaGuard proxy setup on Google Cloud, follow the QuotaGuard and Google Cloud Run / Cloud Functions integration guide, then port the handler above. A ready-to-paste Google Cloud Function example is not published yet. Until it is, the Lambda example is the reference implementation, and the AWS console steps above are the fastest path to a working relay.
Call the Relay From Zoho Deluge, Bubble, or Zapier
Every platform calls the relay the same way: a request to the function URL carrying X-Relay-Key and X-Target-URL. The examples below cover the three most common no-proxy platforms.
Zoho Deluge
Use invokeUrl and pass the two relay headers plus whatever the target API needs:
response = invokeUrl
[
url: "https://<your-function-url>.lambda-url.<region>.on.aws/"
type: POST
headers: {"X-Relay-Key": "<your secret>", "X-Target-URL": "https://api.example.com/endpoint", "Content-Type": "application/json"}
parameters: payload.toString()
];
Bubble
In Bubble’s API Connector, add a new API call. Set the method and point the URL at your relay’s function URL. Add two headers, X-Relay-Key with your secret and X-Target-URL with the target endpoint, plus any Content-Type or Authorization header the target expects. Bubble’s API Connector configuration changes over time, so confirm the current header and body field names against Bubble’s own documentation.
Zapier
In a Zapier Webhooks by Zapier action or a built-in app action, send the request to your relay’s function URL with the same two headers, X-Relay-Key and X-Target-URL. One exception: a Python Code by Zapier step can set a proxy directly on its HTTP client, so if you are already writing Python there, point it at your QUOTAGUARDSTATIC_URL and skip the relay. Confirm current field names against Zapier’s own documentation.
curl
To test from your own machine:
curl https://<your-function-url>.lambda-url.<region>.on.aws/ \
-H "X-Relay-Key: <your secret>" \
-H "X-Target-URL: https://ip.quotaguard.com"
Test the Relay Against ip.quotaguard.com
Point X-Target-URL at https://ip.quotaguard.com. It returns the IP your request came from, which must be one of the two static IPs in your dashboard:
{"ip":"<one of your two QuotaGuard static IPs>"}
Call it more than once and you will see both IPs, because the pair is load-balanced. Those two IPs are what you give the target API for its allowlist. Both are active, so allowlist both.
Troubleshooting
- 403 Forbidden from the relay. The
X-Relay-Keyheader is missing or does not matchRELAY_KEY. The function URL lowercases header names, which the example code already accounts for. Confirm the key matches exactly. - 400 Missing X-Target-URL. Add the
X-Target-URLheader with the full target URL, includinghttps://. - Wrong IP returned, not one from your dashboard. The request reached the target directly instead of through the relay, or
QUOTAGUARDSTATIC_URLis not set on the function. Confirm your platform is calling the relay URL, not the target, and that the environment variable is present. - Timeout. Raise the function timeout above the 3-second default. The example sets 30 seconds. A slow target API can still exceed that, so tune it to the target.
- The target API still rejects the request (a 401 or 403 from the target, not the relay). Allowlist both static IPs from your dashboard. Both are active behind the load balancer, so allowlisting only one lets roughly half your requests through.
- 407 Proxy Authentication Required. The credentials in
QUOTAGUARDSTATIC_URLare wrong. Copy the exact Connection URL from your dashboard. - POST body arrives empty. Make sure
Content-Typeis forwarded. The relay base64-decodes bodies when the platform sendsisBase64Encoded, and passesContent-TypeandAuthorizationstraight through.
QuotaGuard Static vs QuotaGuard Shield
| Feature | QuotaGuard Static | QuotaGuard Shield |
|---|---|---|
| Protocol | HTTP / HTTPS / SOCKS5 | HTTPS / SOCKS5 over TLS |
| Customer-to-proxy hop | Plaintext | TLS-encrypted |
| HTTPS payload | Tunneled end-to-end, never decrypted at the proxy | Tunneled end-to-end, never decrypted at the proxy |
| Best for | Most apps | Regulated data or environments that require TLS on every hop |
| Starting price | $19/month | $29/month |
Static is right for the relay pattern on this page. The relay sends HTTPS to the target, which stays encrypted end to end whether you use Static or Shield. Choose Shield only if the workload handles regulated data, such as HIPAA, PCI-DSS, or SOC 2 material, or your environment requires TLS between the relay and the proxy itself. To switch, set the environment variable to your Shield Connection URL (an https:// URL on port 9294) and change the ProxyManager scheme from http to https.
Frequently Asked Questions
Can Zoho Deluge use a static IP if it can’t set an HTTP proxy?
Yes. Deluge cannot set a proxy and cannot run a sidecar, so you host a small relay function that does. Deluge calls the relay’s URL with an invokeUrl request, the relay forwards the call through QuotaGuard, and the target API sees your two static IPs. This is the only working approach for Deluge, because there is no proxy setting to configure inside Zoho.
Does the relay’s own server IP need to be allowlisted?
No. The target API only ever sees QuotaGuard’s two static IPs, because the relay forwards every request through the QuotaGuard proxy. The relay host’s outbound IP is never in the path the target inspects, so you allowlist the two QuotaGuard IPs from your dashboard and nothing else.
How many static IPs do I allowlist?
Two. Every QuotaGuard subscription includes two load-balanced static IPs, and both are active at once. Allowlist both with the target API. If you allowlist only one, roughly half your requests will be refused when the load balancer uses the other IP.
Do I need QuotaGuard Shield for this relay?
No, in almost every case Static is correct. The request from the relay to the target is HTTPS and stays encrypted end to end on Static already. Use Shield only when the data is regulated, such as HIPAA, PCI-DSS, or SOC 2 material, or when your environment requires TLS on the hop between the relay and the proxy itself.
Does this relay work for Bubble and Zapier as well as Zoho?
Yes. The relay is platform-neutral. Any platform that can send an HTTP request with custom headers can call it, including Bubble’s API Connector and Zapier’s Webhooks and Code steps. You deploy one relay and reuse it across every no-proxy platform you run.
Do I need a separate relay for each target API?
No. One relay handles any number of targets, because the destination is chosen per request by the X-Target-URL header. Deploy the relay once, then send each call to whichever API you need to reach.
Ready to Get Started?
Get in touch or create a free trial account.
Read: QuotaGuard and Retool Integration Guide