Work in progress. Core proxy, key rotation, and dashboard are production-ready. See Planned for what's coming next.
Stop your outbound campaigns from dying on rate limits. KeyProxy sits between your automation stack and any upstream API — when one key gets throttled, it instantly rotates to the next. Your campaigns keep running.
Built for cold outbound agencies and operators running at scale.
You're running AI personalization across 5,000 leads. Your OpenAI key hits its rate limit at lead 800. Everything stops.
Or you have three Apollo accounts, two Hunter.io accounts, and no clean way to load-balance requests across all of them without custom code per integration.
KeyProxy gives you a single endpoint per API. Drop in as many keys as you have. It round-robins through active keys, detects rate limits by HTTP status code, cools down exhausted keys automatically, and retries with the next available key — all without touching your campaign setup.
Your automation tool
│
▼
https://your-keyproxy.vercel.app/api/proxy/CONFIG_ID/...
│
├── Key 1: active → try → 429 → mark exhausted, cooldown 60min
├── Key 2: active → try → 200 → forward response back to you
├── Key 3: cooldown → skip
└── Key 4: active → standby
One config per upstream API. Unlimited keys per config. Unlimited configs.
Key rotation & rate limit handling
- Round-robin rotation across all active keys
- Configurable rate-limit status codes (default: 429)
- Automatic cooldown and recovery — exhausted keys re-activate after a window you set
- Up to 200 retry attempts per request before returning 503
- Reset all keys to active instantly from the dashboard
Dashboard & visibility
- Real-time active / exhausted / cooldown counts per config
- Per-key request counts and status
- Audit log — every rotation, reset, and key change is recorded
- Debug endpoint (
/api/debug/...) for inspecting proxy behavior without affecting production
Key management
- Bulk key import — paste a list, duplicates removed automatically
- Add or remove individual keys without downtime
- Master key rotation — generate a new UUID for any config without touching your key pool
Auth & teams
- One-time setup screen creates the first admin on fresh deploys — no manual DB seeding
- HMAC-signed session cookies, 7-day sessions, no server-side session table
- Multi-user: admins can create accounts, reset passwords, and grant/revoke admin access
- Always keeps at least one admin — can't lock yourself out
Works with any API
- Full HTTP passthrough: GET, POST, PUT, PATCH, DELETE
- Forwards all headers and request body unchanged
- Configurable auth header name and prefix per config (e.g.
Authorization: Bearer,x-api-key:, etc.) - Tested against OpenAI, Anthropic, Apollo, Hunter.io, and generic REST APIs
These are confirmed gaps being actively worked on — not wishlist items:
- Webhook notification when all keys in a pool are simultaneously exhausted
- Per-key usage analytics with time-series charts
- CSV key import
- Per-config request logs with filtering and pagination
- Sentry / error monitoring integration
-
.env.examplefile for easier self-hosting - Structured logging in auth and proxy handlers
- Extract shared form styles to a single module (current duplication across 5 components)
One-click on Vercel:
You need:
- A Neon database (free tier works)
- A random 32-byte hex string for
SESSION_SECRET
The schema creates itself on first run.
Self-host:
git clone https://github.com/athm793/keyproxy
cd keyproxy
npm install
# Create .env.local
DATABASE_URL=postgresql://... # Neon connection string (sslmode=require)
SESSION_SECRET=<random 64 hex chars>
npm run dev # http://localhost:3000Generate a session secret:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Replace the base URL of any API call with your KeyProxy endpoint:
# Before — direct to OpenAI, one key, dies on rate limits
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer sk-abc123..."
# After — routes through KeyProxy, rotates across your key pool
curl https://your-keyproxy.vercel.app/api/proxy/CONFIG_ID/v1/chat/completions \
-H "x-master-key: YOUR_MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "messages": [...]}'Your master key authenticates you to KeyProxy. KeyProxy strips it, injects the next available API key, and forwards the request upstream. Your automation tool never touches the underlying keys.
Alternative — pass the master key as a Bearer token (useful for tools that only support Authorization header):
curl https://your-keyproxy.vercel.app/api/proxy/CONFIG_ID/v1/models \
-H "Authorization: Bearer YOUR_MASTER_KEY"One config = one upstream API. Here's a typical agency setup:
| Config name | Target URL | Keys in pool |
|---|---|---|
| OpenAI - Personalization | https://api.openai.com |
8 keys across 4 accounts |
| Hunter.io - Email Finder | https://api.hunter.io |
3 team keys |
| Apollo - Enrichment | https://api.apollo.io |
5 org keys |
Point every tool in your stack at the matching KeyProxy endpoint. Add more keys as you acquire them. The proxy handles the rest.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | Neon PostgreSQL connection string |
SESSION_SECRET |
Yes | 32+ byte random hex string for signing session cookies. Rotating this logs everyone out. |
Fresh deploy → visit the app → you're redirected to /setup. Create your admin account. That's it — no manual DB steps, no seed scripts. Subsequent team members get accounts from the Manage Users screen (admin only).
| Method | Route | Description |
|---|---|---|
| GET / POST | /api/configs |
List or create proxy configs |
| GET / PATCH / DELETE | /api/configs/[id] |
Get, update, or delete a config |
| POST | /api/configs/[id]/keys |
Add keys to a config |
| DELETE | /api/configs/[id]/keys/[keyId] |
Remove a specific key |
| POST | /api/configs/[id]/reset |
Reset all keys to active |
| POST | /api/configs/[id]/rotate-key |
Rotate the config's master key |
| POST | /api/configs/[id]/test |
Test connectivity to the target API |
| ALL | /api/proxy/[configId]/[...path] |
Main proxy endpoint |
| ALL | /api/debug/[configId]/[...path] |
Debug proxy with verbose logging |
| GET | /api/health |
Health check |
| POST | /api/auth/setup |
One-time: create first admin |
| POST | /api/auth/login |
Log in |
| POST | /api/auth/logout |
Log out |
| GET | /api/auth/me |
Current session user |
| GET / POST | /api/users |
List or create users (admin only) |
| PATCH / DELETE | /api/users/[id] |
Update or delete a user (admin only) |
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| UI | React 19, Tailwind CSS 4 |
| Language | TypeScript 5 |
| Database | Neon (PostgreSQL serverless) |
| DB client | @neondatabase/serverless |
| Session auth | HMAC-signed cookie, scrypt passwords |
| Deployment | Vercel |
proxy_configs — id, name, target_base_url, auth_header_name, auth_header_prefix, rate_limit_codes[], cooldown_minutes, master_key, created_at
api_keys — id, config_id, key_value, order_index, status (active|exhausted|cooldown), exhausted_at, request_count, created_at
audit_log — id, config_id, action, detail, created_at
users — id, email, password_hash, name, is_admin, created_at, updated_at
src/
├── middleware.ts # Session-cookie auth gate
├── app/
│ ├── page.tsx # Dashboard — all configs
│ ├── login/page.tsx # Login
│ ├── setup/page.tsx # First-run admin setup
│ ├── admin/users/page.tsx # User management (admin)
│ ├── configs/new/page.tsx # Create config
│ ├── configs/[id]/page.tsx # Manage keys + settings
│ └── api/
│ ├── proxy/[configId]/[...path]/ # Main proxy endpoint
│ ├── debug/[configId]/[...path]/ # Debug proxy
│ ├── configs/ # Config CRUD
│ ├── auth/ # login, logout, me, setup
│ ├── users/ # User management
│ └── health/ # Health check
├── components/
│ ├── ConfigCard.tsx
│ ├── KeysTable.tsx
│ ├── AddKeysForm.tsx
│ ├── EditConfigForm.tsx
│ ├── MasterKeyDisplay.tsx
│ ├── CurlExample.tsx
│ ├── StatsBar.tsx
│ ├── AuditLog.tsx
│ ├── LoginForm.tsx
│ ├── SetupForm.tsx
│ ├── UserMenu.tsx
│ └── UsersManager.tsx
└── lib/
├── db.ts # Neon DB + schema init
├── usersDb.ts # User CRUD
├── auth.ts # Session cookie helpers
├── sessionToken.ts # Edge-safe HMAC tokens
├── passwords.ts # scrypt hashing
├── proxy.ts # Key rotation + forwarding
└── types.ts # TypeScript interfaces
Rotation logic: pick lowest order_index active key → forward request → if response code is in rate_limit_codes, mark exhausted, schedule cooldown recovery, retry with next key → return 503 only if all keys are simultaneously exhausted.