A developer built an API and needed key management. He started with a simple API key table in his database. Then he needed rate limiting. Then usage tracking. Then key rotation. Then per-key permissions. 3 months later, he had a full key management system — and zero time left for his actual product.
Unkey does all of this in 5 minutes.
What Unkey Offers for Free
Unkey free tier:
- 1,000 active keys
- 150,000 verifications/month
- Rate limiting — per-key limits
- Usage tracking — per-key analytics
- Temporary keys — auto-expire after N seconds/days
- Key metadata — attach any data to a key
- Ratelimit as a service — use even without keys
- Open source, self-hostable
Quick Start
npm install @unkey/api
import { Unkey } from '@unkey/api';
const unkey = new Unkey({ rootKey: process.env.UNKEY_ROOT_KEY });
Create API Keys
// Create a key for a user
const { result } = await unkey.keys.create({
apiId: 'api_123',
prefix: 'sk',
name: 'Alice Production Key',
ownerId: 'user_alice',
meta: {
plan: 'pro',
permissions: ['read', 'write']
},
ratelimit: {
type: 'fast',
limit: 100,
refillRate: 100,
refillInterval: 60000 // 100 requests per minute
},
remaining: 10000, // Max 10K total uses
expires: Date.now() + 30 * 24 * 60 * 60 * 1000 // 30 days
});
console.log(result.key); // sk_1234567890abcdef
// Give this key to your user
Verify Keys (in Your API)
// Middleware for your API
async function verifyApiKey(req, res, next) {
const key = req.headers['authorization']?.replace('Bearer ', '');
if (!key) return res.status(401).json({ error: 'Missing API key' });
const { result, error } = await unkey.keys.verify({ key });
if (error || !result.valid) {
return res.status(403).json({
error: 'Invalid API key',
code: result?.code // 'NOT_FOUND', 'RATE_LIMITED', 'USAGE_EXCEEDED', 'EXPIRED'
});
}
// Key is valid — attach metadata to request
req.keyOwner = result.ownerId;
req.keyMeta = result.meta;
req.remaining = result.remaining;
// Rate limit headers
res.set('X-RateLimit-Limit', String(result.ratelimit?.limit));
res.set('X-RateLimit-Remaining', String(result.ratelimit?.remaining));
next();
}
app.use('/api/*', verifyApiKey);
REST API
# Create a key
curl -X POST 'https://api.unkey.dev/v1/keys.createKey' \
-H 'Authorization: Bearer YOUR_ROOT_KEY' \
-H 'Content-Type: application/json' \
-d '{
"apiId": "api_123",
"prefix": "sk",
"name": "Test Key",
"ratelimit": {"type": "fast", "limit": 10, "refillRate": 10, "refillInterval": 60000}
}'
# Verify a key
curl -X POST 'https://api.unkey.dev/v1/keys.verifyKey' \
-H 'Content-Type: application/json' \
-d '{"key": "sk_1234567890abcdef"}'
# Get key details
curl 'https://api.unkey.dev/v1/keys.getKey?keyId=KEY_ID' \
-H 'Authorization: Bearer YOUR_ROOT_KEY'
# Revoke a key
curl -X POST 'https://api.unkey.dev/v1/keys.deleteKey' \
-H 'Authorization: Bearer YOUR_ROOT_KEY' \
-H 'Content-Type: application/json' \
-d '{"keyId": "KEY_ID"}'
Rate Limiting as a Service
import { Ratelimit } from '@unkey/ratelimit';
const limiter = new Ratelimit({
rootKey: process.env.UNKEY_ROOT_KEY,
namespace: 'api.requests',
limit: 100,
duration: '60s'
});
// Check rate limit (works without API keys)
const { success, limit, remaining, reset } = await limiter.limit(`user_${userId}`);
if (!success) {
return res.status(429).json({ error: 'Rate limited', retryAfter: reset });
}
Why Unkey
| Unkey | DIY API Keys |
|---|---|
| Rate limiting built in | Build rate limiter |
| Usage tracking | Build analytics |
| Key expiration | Cron job to clean up |
| Per-key metadata | Extra database table |
| 5 min setup | 3+ months |
Building APIs for data collection? Check out my web scraping actors on Apify.
Need API key management? Email me at spinov001@gmail.com.
Top comments (0)