Authentication
Ozwell uses API keys to authenticate requests. This guide covers key types, security best practices, and implementation patterns.
API Key Types
Ozwell provides two types of API keys for different use cases:
| Key Type | Prefix | Use Case | Security Level |
|---|---|---|---|
| General-Purpose | ozw_ | Server-side, full API access | Server-only |
| Scoped | ozw_scoped_ | Client-side, limited access | Client-safe |
General-Purpose Keys
Full-access keys for server-side integrations:
- ✅ Access all API endpoints
- ✅ All models and capabilities
- ✅ No agent restrictions
- ⚠️ Never expose client-side
# Server-side usage only
export OZWELL_API_KEY="ozw_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Scoped Keys
Restricted keys for client-side (frontend) integrations:
- ✅ Tied to specific agent(s)
- ✅ Permission-limited
- ✅ Safe for browser use
- ✅ Domain restrictions available
// Safe for frontend use
const apiKey = 'ozw_scoped_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
Creating API Keys
Via Dashboard
- Log in to Ozwell Dashboard
- Navigate to Settings → API Keys
- Click Create API Key or Create Scoped Key
- Configure permissions (for scoped keys)
- Copy the key immediately — it won't be shown again
Via API (Coming Soon)
curl https://api.ozwell.ai/v1/api-keys \
-H "Authorization: Bearer $OZWELL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Server",
"type": "general",
"permissions": ["*"]
}'
Using API Keys
Authorization Header
Include the API key in the Authorization header:
curl https://api.ozwell.ai/v1/chat/completions \
-H "Authorization: Bearer ozw_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4", "messages": [{"role": "user", "content": "Hello"}]}'
SDK Configuration
import { OzwellClient } from '@ozwell/api';
const client = new OzwellClient({
apiKey: process.env.OZWELL_API_KEY,
});
OpenAI SDK Compatibility
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.OZWELL_API_KEY,
baseURL: 'https://api.ozwell.ai/v1',
});
Security Best Practices
Never Expose Keys in Code
// ❌ BAD - Key in source code
const client = new OzwellClient({
apiKey: 'ozw_abc123...',
});
// ✅ GOOD - Key from environment
const client = new OzwellClient({
apiKey: process.env.OZWELL_API_KEY,
});
Use Environment Variables
# .env (never commit this file)
OZWELL_API_KEY=ozw_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# .env.example (commit this as a template)
OZWELL_API_KEY=your_api_key_here
// Load from environment
import 'dotenv/config';
const client = new OzwellClient({
apiKey: process.env.OZWELL_API_KEY,
});
Separate Keys by Environment
Use different keys for each environment:
# Development
OZWELL_API_KEY=ozw_dev_xxxxxxxx
# Staging
OZWELL_API_KEY=ozw_staging_xxxxxxxx
# Production
OZWELL_API_KEY=ozw_prod_xxxxxxxx
Regular Key Rotation
Rotate API keys periodically:
- Create a new key in the dashboard
- Update your application configuration
- Deploy the change
- Verify the new key works
- Revoke the old key
Scoped Key Domain Restrictions
For frontend integrations, restrict scoped keys to specific domains:
- Go to Settings → API Keys
- Edit your scoped key
- Add allowed domains (e.g.,
example.com,*.example.com) - Requests from other domains will be rejected
Error Handling
Invalid API Key
{
"error": {
"message": "Invalid API key provided",
"type": "authentication_error",
"code": "invalid_api_key"
}
}
HTTP Status: 401 Unauthorized
Missing API Key
{
"error": {
"message": "API key is required",
"type": "authentication_error",
"code": "missing_api_key"
}
}
HTTP Status: 401 Unauthorized
Insufficient Permissions
{
"error": {
"message": "API key does not have access to this resource",
"type": "permission_error",
"code": "insufficient_permissions"
}
}
HTTP Status: 403 Forbidden
Handling in Code
import { OzwellClient, OzwellError } from '@ozwell/api';
const client = new OzwellClient({
apiKey: process.env.OZWELL_API_KEY,
});
try {
const response = await client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }],
});
} catch (error) {
if (error instanceof OzwellError) {
switch (error.code) {
case 'invalid_api_key':
console.error('Check your API key configuration');
break;
case 'insufficient_permissions':
console.error('This key lacks required permissions');
break;
default:
console.error('API error:', error.message);
}
}
throw error;
}
Rate Limiting
API keys are rate-limited. When exceeded:
HTTP Status: 429 Too Many Requests
Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1699000060
Retry-After: 30
Response:
{
"error": {
"message": "Rate limit exceeded. Please retry after 30 seconds.",
"type": "rate_limit_error",
"code": "rate_limit_exceeded"
}
}
Handling Rate Limits
async function makeRequestWithRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error instanceof OzwellError && error.code === 'rate_limit_exceeded') {
const retryAfter = error.headers?.['retry-after'] || 30;
console.log(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
} else {
throw error;
}
}
}
throw new Error('Max retries exceeded');
}
Key Management API
List Keys (Coming Soon)
GET /v1/api-keys
Revoke Key (Coming Soon)
DELETE /v1/api-keys/{key_id}