API Keys
Programmatically manage API keys for authentication and access control.
Why Manage Keys Programmatically?
- Automation: Create keys for new environments automatically
- Security: Rotate keys regularly without manual intervention
- Scope Control: Create limited-scope keys for specific services
- Monitoring: Track key usage and detect anomalies
Create an API Key
const key = await client.apiKeys.create({
name: 'Production Key',
scopes: ['inboxes:write', 'messages:write']
})
console.log(key.id)
// → key_abc123
console.log(key.key)
// → mx_def456ghi789 (save this!)
console.log(key.scopes)
// → ['inboxes:write', 'messages:write']Save the Key
The actual API key (key.key) is only shown once during creation. Save it securely - you won't be able to retrieve it again!
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable name |
scopes | string[] | Yes | Permissions for this key |
description | string | No | Optional description |
usage_limit_per_day | number | No | Daily usage limit |
Available Scopes
| Scope | Permissions |
|---|---|
inboxes:read | List and view inboxes |
inboxes:write | Create, update, and delete inboxes |
messages:read | List and view messages |
messages:write | Send and delete messages |
webhooks:read | List and view webhooks |
webhooks:write | Create, update, and delete webhooks |
api_keys:read | List and view API keys |
api_keys:write | Create and revoke API keys |
Read-Only Key
Create a key with only read permissions:
const monitoringKey = await client.apiKeys.create({
name: 'Monitoring Dashboard',
scopes: ['inboxes:read', 'messages:read'],
description: 'Read-only access for monitoring'
})Principle of Least Privilege
Always create keys with the minimum scopes required. This limits damage if a key is compromised.
Send-Only Key
Create a key that can only send emails:
const senderKey = await client.apiKeys.create({
name: 'Email Sender Service',
scopes: ['messages:write'],
description: 'Can only send emails, not read them'
})Key with Usage Limit
Prevent runaway costs with daily usage limits:
const testKey = await client.apiKeys.create({
name: 'Test Environment',
scopes: ['inboxes:write', 'messages:write'],
usage_limit_per_day: 100, // Max 100 API calls per day
description: 'Limited key for testing'
})List API Keys
const response = await client.apiKeys.list({
limit: 20,
offset: 0
})
for (const key of response.data) {
console.log(`${key.name} (${key.id})`)
console.log(`Scopes: ${key.scopes.join(', ')}`)
console.log(`Created: ${key.created_at}`)
console.log('---')
}Get a Single Key
const key = await client.apiKeys.get('key_abc123')
console.log(key.name)
console.log(key.scopes)
console.log(key.usage_limit_per_day)Can't Retrieve Key Value
You can view key metadata (name, scopes, etc.) but not the actual key value (mx_...). The key value is only shown during creation.
Check Key Usage
Monitor how much an API key is being used:
const usage = await client.apiKeys.getUsage('key_abc123')
console.log(`Today: ${usage.today} calls`)
console.log(`This week: ${usage.this_week} calls`)
console.log(`This month: ${usage.this_month} calls`)
console.log(`All time: ${usage.all_time} calls`)Usage Monitoring Example
// Alert on high usage
const keys = await client.apiKeys.list()
for (const key of keys.data) {
const usage = await client.apiKeys.getUsage(key.id)
if (usage.today > 5000) {
console.warn(`⚠️ High usage on "${key.name}": ${usage.today} calls today`)
}
if (key.usage_limit_per_day) {
const percentUsed = (usage.today / key.usage_limit_per_day) * 100
console.log(`"${key.name}": ${percentUsed.toFixed(1)}% of daily limit`)
}
}Revoke an API Key
Permanently disable a key:
await client.apiKeys.revoke('key_abc123')This is Permanent
Revoking a key:
- Immediately stops all requests using that key
- Cannot be undone
- Requires creating a new key to restore access
Make sure you update any services using the old key first!
Rotate Keys
Best practice: regularly rotate your API keys.
async function rotateKey(oldKeyId: string) {
// 1. Create new key with same scopes
const oldKey = await client.apiKeys.get(oldKeyId)
const newKey = await client.apiKeys.create({
name: `${oldKey.name} (rotated ${new Date().toISOString().split('T')[0]})`,
scopes: oldKey.scopes,
description: oldKey.description,
usage_limit_per_day: oldKey.usage_limit_per_day
})
console.log('New key created:', newKey.key)
console.log('Update your environment variables with this key!')
console.log('Then revoke the old key:')
console.log(` client.apiKeys.revoke('${oldKeyId}')`)
return newKey
}
// Usage
await rotateKey('key_abc123')Key Rotation Strategy
Manual Rotation
// 1. Create new key
const newKey = await client.apiKeys.create({
name: 'Production Key (2025-01)',
scopes: ['inboxes:write', 'messages:write']
})
// 2. Update your .env file with newKey.key
// 3. Deploy updated environment variable
// 4. Revoke old key after verification
await client.apiKeys.revoke('old_key_id')Automated Rotation (90 days)
async function autoRotateKeys() {
const keys = await client.apiKeys.list()
const ninetyDaysAgo = new Date()
ninetyDaysAgo.setDate(ninetyDaysAgo.getDate() - 90)
for (const key of keys.data) {
const createdAt = new Date(key.created_at)
if (createdAt < ninetyDaysAgo) {
console.log(`Key "${key.name}" is ${Math.floor((Date.now() - createdAt.getTime()) / (1000 * 60 * 60 * 24))} days old`)
// Create replacement
const newKey = await client.apiKeys.create({
name: `${key.name} (rotated)`,
scopes: key.scopes,
description: key.description
})
console.log(`Created replacement: ${newKey.id}`)
console.log(`New key: ${newKey.key}`)
console.log(`Update your environment, then revoke: ${key.id}`)
}
}
}
// Run monthly via cron
autoRotateKeys().catch(console.error)Complete Example
import { MyxaraClient } from '@myxara/sdk-js'
const client = new MyxaraClient({
apiKey: process.env.MYXARA_API_KEY!
})
async function setupAPIKeys() {
// Production key - full access
const prodKey = await client.apiKeys.create({
name: 'Production Service',
scopes: [
'inboxes:write',
'messages:write',
'webhooks:write'
],
description: 'Main production key',
usage_limit_per_day: 50000
})
console.log('Production key:', prodKey.key)
// Analytics key - read only
const analyticsKey = await client.apiKeys.create({
name: 'Analytics Dashboard',
scopes: [
'inboxes:read',
'messages:read'
],
description: 'Read-only for analytics',
usage_limit_per_day: 10000
})
console.log('Analytics key:', analyticsKey.key)
// Email sender key - send only
const senderKey = await client.apiKeys.create({
name: 'Email Sender Worker',
scopes: ['messages:write'],
description: 'Send emails only',
usage_limit_per_day: 30000
})
console.log('Sender key:', senderKey.key)
// Test key - limited usage
const testKey = await client.apiKeys.create({
name: 'Test Environment',
scopes: ['inboxes:write', 'messages:write'],
description: 'For testing',
usage_limit_per_day: 100
})
console.log('Test key:', testKey.key)
// Monitor usage
console.log('\nCurrent usage:')
const keys = await client.apiKeys.list()
for (const key of keys.data) {
const usage = await client.apiKeys.getUsage(key.id)
console.log(`${key.name}: ${usage.today} calls today`)
}
}
setupAPIKeys().catch(console.error)Security Best Practices
1. Never Commit Keys to Git
# .gitignore
.env
.env.local
*.key
secrets/2. Use Environment Variables
// ✅ Good
const client = new MyxaraClient({
apiKey: process.env.MYXARA_API_KEY!
})
// ❌ Bad
const client = new MyxaraClient({
apiKey: 'mx_hardcoded_key'
})3. Scope Keys Appropriately
// ✅ Good - minimal scopes
const webhookKey = await client.apiKeys.create({
name: 'Webhook Processor',
scopes: ['messages:read'] // Only what's needed
})
// ❌ Bad - excessive scopes
const webhookKey = await client.apiKeys.create({
name: 'Webhook Processor',
scopes: ['*'] // Too broad!
})4. Set Usage Limits
// ✅ Good - protected against abuse
const key = await client.apiKeys.create({
name: 'Public API',
scopes: ['messages:write'],
usage_limit_per_day: 1000 // Fail-safe
})5. Monitor and Alert
// Check usage daily
async function checkUsage() {
const keys = await client.apiKeys.list()
for (const key of keys.data) {
const usage = await client.apiKeys.getUsage(key.id)
if (key.usage_limit_per_day) {
const percent = (usage.today / key.usage_limit_per_day) * 100
if (percent > 80) {
// Send alert
console.warn(`⚠️ Key "${key.name}" at ${percent.toFixed(1)}% of limit`)
}
}
}
}Error Handling
import { AuthenticationError, APIError } from '@myxara/sdk-js'
try {
const key = await client.apiKeys.create({
name: 'New Key',
scopes: ['inboxes:write']
})
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Not authorized to create API keys')
} else if (error instanceof APIError) {
if (error.status === 429) {
console.error('Rate limited - too many keys created')
} else {
console.error('API error:', error.message)
}
}
}TypeScript Types
import type {
APIKey,
CreateAPIKeyParams,
APIKeyUsage,
ListResponse
} from '@myxara/sdk-js'
const params: CreateAPIKeyParams = {
name: 'My Key',
scopes: ['messages:write'],
usage_limit_per_day: 1000
}
const key: APIKey = await client.apiKeys.create(params)
const usage: APIKeyUsage = await client.apiKeys.getUsage(key.id)
const response: ListResponse<APIKey> = await client.apiKeys.list()Next Steps
- Authentication → - Learn about API key authentication
- Error Handling → - Handle authentication errors
- Client → - Configure the SDK client