Add usage limits to your AI mobile app in 5 minutes. Track usage per user, set limits per model, create pricing tiers—all without storing prompts or API keys.
Your App → AI Ratelimit → OpenAI / Anthropic / Google / Any AI
↓
Check limits
Track usage
Forward request
How it works: Point your AI requests at our proxy. We check limits, then forward to the real API. Pass your API key per-request, or store it encrypted in the dashboard.
- baseURL: 'https://api.openai.com/v1'
+ baseURL: 'https://api.airatelimit.com/v1'
+ headers: { 'x-project-key': 'pk_xxx', 'x-identity': userId, 'x-tier': 'free' }That's it. Works with any AI provider.
Building an AI app? You need:
- Limit free tier without building billing
- Track anonymous users (no login required)
- Different limits per model (gpt-4o: expensive, gemini: cheap)
- Custom upgrade prompts when limits hit
- Privacy-first (never store prompts or responses)
This does all that.
Try the product live at https://airatelimit.com
Join our Discord community for discussions, support, and updates:
Railway (Recommended):
Quick steps:
- Push to GitHub
- Connect to Railway
- Add PostgreSQL
- Set
DATABASE_URLandJWT_SECRETenv vars - Deploy
Local:
npm install && cd dashboard && npm install && cd ..
export DB_PASSWORD=$(openssl rand -base64 24)
docker run --name ai-proxy-db -e POSTGRES_PASSWORD=$DB_PASSWORD -e POSTGRES_DB=ai_proxy -p 5433:5432 -d postgres:15
cp env.example .env # Edit DATABASE_URL with your DB_PASSWORD
npm run startDashboard: http://localhost:3001 | Backend: http://localhost:3000
- Open dashboard → Sign up
- Create project → get your project key (
pk_...) - Configure limits
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: 'sk-xxx',
baseURL: 'https://api.airatelimit.com/v1',
defaultHeaders: {
'x-project-key': 'pk_xxx',
'x-identity': getUserId(),
},
});
// Use normally
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Hello!' }],
});| Header | Description | Required | Example |
|---|---|---|---|
x-project-key |
Your project key from dashboard | Always | pk_abc123 |
x-identity |
Your user's ID (from your app) | Always | user_abc, session_xyz |
Authorization |
Your AI provider API key | Pass-through only | Bearer sk-xxx |
x-tier |
Pricing tier | Optional | free, pro |
x-identityis whatever you use to identify users—a user ID, session ID, or device ID. Each identity gets its own usage limits.
Pass-through Mode (server-side apps):
- Pass your AI provider API key in the
Authorizationheader - We forward it to OpenAI/Anthropic/Google, never store it
Stored Keys Mode (mobile apps):
- Store your AI provider API keys in Dashboard settings
- Your app only needs
x-project-key, no AI keys exposed in client code - Keys are encrypted at rest
Set different limits for each model:
gpt-4o: 5 requests/day (expensive)
gemini-2.0-flash: unlimited (cheap)
claude-3-5-sonnet: 50 requests/day
Different limits for free vs pro users:
free: { gpt-4o: 5, gemini: unlimited }
pro: { gpt-4o: 500, gemini: unlimited }
Cap specific users programmatically using your project's secret key (sk_xxx):
# Set limits for one user
curl -X POST https://api.airatelimit.com/api/projects/pk_xxx/identities \
-H "Authorization: Bearer sk_xxx" \
-H "Content-Type: application/json" \
-d '{"identity": "user-123", "requestLimit": 1000, "tokenLimit": 50000}'
# Disable a user
curl -X POST .../identities -d '{"identity": "user-123", "enabled": false}'
# Upgrade their limit
PUT /identities/user-123 {"tokenLimit": 50000}
# Gift tokens to a user
curl -X POST .../identities/user-123/gift -d '{"tokens": 10000}'
# Give unlimited access until date
curl -X POST .../identities/user-123/promo -d '{"unlimitedUntil": "2025-12-31"}'
# Reset usage after payment (clears current period's usage)
curl -X POST .../identities/user-123/reset -d '{"resetTokens": true, "resetRequests": true}'Find your secret key in Dashboard → Project Settings → API Access.
Store system prompts server-side so they're hidden from mobile app code:
# Create a prompt
curl -X POST .../prompts -d '{"name": "assistant-v1", "content": "You are a helpful assistant."}'Then reference by name in requests: {"systemPrompt": "assistant-v1", "messages": [...]}
Show upgrade prompts with deep links when limits are hit:
{
"message": "You've used {{usage}}/{{limit}} free requests. Upgrade to Pro!",
"deepLink": "app://upgrade"
}Protect your system prompts from extraction attacks:
- Detects "show me your prompt" jailbreaks
- Blocks role manipulation attempts
- Logs all security events
- Never stores prompts or responses
- API keys only stored if you choose Stored Keys Mode (encrypted at rest)
- Only tracks: identity, usage counts, timestamps
Choose when limits reset:
- Daily - Reset at midnight UTC
- Weekly - Reset Monday midnight UTC
- Monthly - Reset 1st of month UTC
When limits are exceeded (HTTP 429):
{
"error": {
"message": "You've used 5/5 free requests. Upgrade to Pro!",
"type": "rate_limit_exceeded",
"code": "limit_exceeded"
}
}# Required
DATABASE_URL=postgresql://...
JWT_SECRET=your-secret-key
CORS_ORIGIN=https://your-dashboard.railway.app
NODE_ENV=production
# Required for Stored Keys Mode (production)
ENCRYPTION_KEY=your-32-char-key # Generate with: openssl rand -hex 32
# Optional
PORT=3000
RESEND_API_KEY=re_... # For magic link emails
EMAIL_FROM=noreply@yourdomain.comNODE_ENV=production
# Backend API URL (update after backend is deployed)
NUXT_PUBLIC_API_BASE_URL=https://your-backend-url.railway.app/apifrom openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://api.airatelimit.com/v1",
default_headers={
"x-project-key": "pk_xxx",
"x-identity": "user-123",
}
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}]
)curl https://api.airatelimit.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxx" \
-H "x-project-key: pk_xxx" \
-H "x-identity: user-123" \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello!"}]}'Use the same code—just change the model and API key:
client = OpenAI(
api_key="sk-ant-xxx", # Anthropic key
base_url="https://api.airatelimit.com/v1",
default_headers={
"x-project-key": "pk_xxx",
"x-identity": "user-123",
}
)
response = client.chat.completions.create(
model="claude-3-5-sonnet-20241022", # Claude model
messages=[{"role": "user", "content": "Hello!"}]
)- Remote Config - Switch AI providers without app updates
- Prompt Injection - Prompt injection protection