Most apps call APIs through an SDK: OpenAI, Stripe, Twilio and so on. With Vallkey, the app holds a ghost key instead of the real key. Auto-connect, a small package that starts with your app, sends every request that carries a ghost key to Vallkey. Vallkey checks it against your rules, swaps in the real key and passes the answer back. Your code stays exactly as the SDK's docs show it.
How it works
Your app starts, and auto-connect with it
One setting, a start command or a single line turns it on, depending on where the app runs. Nothing else in your code changes.
A request carries a ghost key
Auto-connect sees the ghost key, in a header, the address or a form body, and sends the request to
api.vallkey.comwith the same path. Requests without a ghost key are not touched: your database, your own APIs and every other call go where they always went.Vallkey checks it and swaps in the real key
Your rules decide: which endpoints, how much per day, from where. Allowed requests reach the provider with the real key, which never leaves Vallkey. Blocked ones get a clear error. Every answer comes back with an
x-guard-request-idheader.
What each host needs
Auto-connect is the same everywhere. What changes is how your host starts the app. Links open the step-by-step guide for that host and language.
| Language | Vercel | Railway | Docker or your own server |
|---|---|---|---|
| Node.js | Next.js: a small setup file. Functions: first linetested | In the start scripttested | NODE_OPTIONS where the app runstested |
| Bun | First line of each functiontested | In the start script | BUN_OPTIONS where the app runstested |
| Python | VALLKEY_AUTO=1 in the variablestested | VALLKEY_AUTO=1 in the variablestested | VALLKEY_AUTO=1tested |
| Ruby | First line of each functiontested | In the Procfiletested | RUBYOPT where the app runstested |
| Java, Kotlin, Scala | Not available | railpack.json or a Dockerfiletested | JAVA_TOOL_OPTIONS and the agent filetested |
| .NET | Not available | railpack.json or a Dockerfiletested | DOTNET_STARTUP_HOOKS and the auto-connect filetested |
| PHP | Not available | A Dockerfile | The extension, with PHP_INI_SCAN_DIRtested |
| Elixir, Erlang | Not available | A Dockerfile | ELIXIR_ERL_OPTIONS and the auto-connect filetested |
| Go, Rust | The SDK's address setting | The SDK's address setting | The SDK's address setting |
Tested means we ran it on a real deployment, or, for Docker, with each language's official SDKs in a container that could reach nothing but Vallkey. The rest follows the same rules but has not been run on that host yet.
The one setting that breaks builds
In Node.js, Bun, Ruby, Java and .NET, auto-connect is turned on by an environment variable: NODE_OPTIONS, BUN_OPTIONS, RUBYOPT, JAVA_TOOL_OPTIONS, DOTNET_STARTUP_HOOKS. Every process of that language reads it, including the ones that build your app.
Vercel, Railway, Render and Heroku use your variables while they build
That variable, set in their variables, reaches npm install, bundle install or the Java build before auto-connect is installed, and the build fails. We saw it on Vercel and Railway. Put it where only the running app reads it: the start command, a Procfile, the first line of a function, railpack.json, or the final stage of a Dockerfile, after your app is built.
| Setting | In the host's variables | Where it goes instead |
|---|---|---|
VALLKEY_AUTO=1 | Safe (Python) | Nowhere else needed |
VALLKEY_ENV | Safe | Names the app, such as production |
VALLKEY_DEBUG=1 | Safe | Logs each request sent to Vallkey, never the key |
NODE_OPTIONS | Breaks the build | The start script, or the first line of a function |
RUBYOPT | Breaks the build | The Procfile, or the first line of a function |
JAVA_TOOL_OPTIONS | Breaks the build | railpack.json, or the final stage of a Dockerfile |
DOTNET_STARTUP_HOOKS | Not where the file is | railpack.json, or the final stage of a Dockerfile |
What auto-connect covers
The HTTP clients auto-connect reaches in each language, and with them the SDKs built on them:
| Language | Covers |
|---|---|
| Node.js and Bun | fetch, http and https: almost every JavaScript SDK |
| Python | httpx, requests, urllib3, boto3, aiohttp, urllib |
| Ruby | Net::HTTP, and Faraday, HTTParty and rest-client on top of it |
| Java, Kotlin, Scala | OkHttp, Apache HttpClient 4 and 5, the JDK HttpClient, HttpURLConnection |
| .NET | HttpClient, on .NET 8 and later |
| PHP | The curl extension: Guzzle, Symfony HttpClient and the SDKs' own clients |
| Elixir, Erlang | Finch (Req), hackney (HTTPoison), httpc (Tesla's default) |
Set it up from your terminal
In your project folder, the CLI tells the language from your files and does or prints each step:
npx vallkey@latest connect # the best way to connect this project; changes nothingnpx vallkey@latest hook # sets up auto-connect: start script, Procfile, Next.js setup file or downloadnpx vallkey@latest doctor # checks this project is ready on this computerIt knows the hosts in this guide: in a Vercel project it shows the first-line setup, for a Node.js app with a start script it offers to change the script, and for Java and .NET it prints the Dockerfile lines and the railpack.json.
Check every deployment
A setup that works on your computer can still miss on a host. One real request from the deployed app settles it:
npx vallkey verify KEY_ID --request-id REQUEST_ID # REQUEST_ID: the x-guard-request-id of your app's answernpx vallkey verify KEY_ID --request-id REQUEST_ID --expect denied # a request your rules block, on a test keynpx vallkey status # every app each key is used fromEach deployment shows up by itself
Auto-connect tells Vallkey where it runs, so a key's Activity tab and vallkey status list each app, such as Vercel · Node.js 24.21 · production or Railway · Python 3.13 · production, with its requests today and anything wrong there.
When to change the address instead
Some code cannot use auto-connect. There, set the SDK's API address to Vallkey, one line, shown on each key's Connect tab:
- Edge functions and Next.js Edge routes: auto-connect works on Node.js only.
- Go and Rust: compiled apps cannot be changed once built.
- .NET native AOT or trimmed builds, which cannot use auto-connect.
- Web pages and mobile apps: use short-lived keys instead, made for code that runs on people's devices.
Step-by-step guides
- Vercel: Next.js, Node.js and Bun functions, Python, Ruby
- Railway: Node.js, Python, Ruby, Java and .NET, with and without Docker
- Auto-connect in the docs: every setting, Docker lines for each language, and the CLI