API Key Management Routes
Overview
This document specifies the frontend routes for tenant API key management, enabling self-service creation, viewing, regeneration, and revocation of API keys for programmatic access to PenguinMails.
Routes Summary
| Route | Purpose | Authentication | Permission |
|---|---|---|---|
/dashboard/settings/developers/api-keys | API key list and management | Required | Tenant user |
/dashboard/settings/developers/api-keys/create | Create new API key (modal) | Required | Tenant user |
/dashboard/settings/developers/api-keys/{key_id} | View API key details (modal) | Required | Tenant user |
Route 1: API Key List
Path: /dashboard/settings/developers/api-keys
Method: GET
Authentication: Required (tenant user session)
Layout: Settings page with sidebar navigation
Page Structure
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Settings Sidebar β API Keys β
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ€
β Profile β βββββββββββββββββββββββββββββββββββββββ β
β Team β β API Keys β β
β Billing β β β β
β Infrastructure β β Manage API keys for programmatic β β
β > Developers β β access to PenguinMails. β β
β - API Keys β β β β
β - Webhooks β β [Create API Key] β β
β Security β βββββββββββββββββββββββββββββββββββββββ β
β β β
β β βββββββββββββββββββββββββββββββββββββββββββ
β β β Name β Key β Permissionsββ
β β βββββββββββββββββΌβββββββββββββΌβββββββββββββ€β
β β β Production β pm_live... β [send] ββ
β β β Server β β [analytics]ββ
β β β β β ββ
β β β Last used: 2h ago Requests: 15,234 ββ
β β β [Copy] [Regenerate] [Revoke] ββ
β β βββββββββββββββββΌβββββββββββββΌβββββββββββββ€β
β β β Staging β pm_live... β [send] ββ
β β β Environment β β ββ
β β β (Revoked) β β ββ
β β β Last used: 1d ago Requests: 5,432 ββ
β β βββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
UI Components
1. Page Header
Elements:
-
Title: βAPI Keysβ
-
Description: βManage API keys for programmatic access to PenguinMails.β
-
Primary action: βCreate API Keyβ button (top right)
2. API Key Table
Columns:
-
Name - User-provided key name
-
Key - Masked key value (
pm_live_abc...xyz) -
Permissions - Badge list of scopes
-
Rate Limit - Requests per minute
-
Status - Active (green) or Revoked (red)
-
Last Used - Relative time (β2 hours agoβ)
-
Actions - Copy, Regenerate, Revoke buttons
Row Details (expandable):
-
Created date
-
Total requests (lifetime)
-
Error count
-
Request chart (last 7 days)
3. Empty State
Displayed when: No API keys exist
Content:
-
Icon: Key icon
-
Title: βNo API keys yetβ
-
Description: βCreate your first API key to start using the PenguinMails API programmatically.β
-
Action: βCreate API Keyβ button
4. Table Actions
Copy Button:
-
Copies masked key to clipboard
-
Shows toast: βKey copied to clipboardβ
-
Note: Full key not available after creation
Regenerate Button:
-
Opens confirmation modal
-
Warning: βOld key will be revoked immediatelyβ
-
Generates new key with same permissions
-
Displays new key once
Revoke Button:
-
Opens confirmation modal
-
Warning: βThis action cannot be undoneβ
-
Marks key as revoked
-
Key remains visible but inactive
API Calls
Load API Keys:
GET /api/v1/platform/api-keys
Response:
{
"api_keys": [
{
"key_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production Server",
"masked_key": "pm_live_a1b...o5p6",
"permissions": ["send_email", "read_analytics"],
"rate_limit": 300,
"status": "active",
"created_at": "2025-11-26T10:00:00Z",
"last_used": "2025-11-26T15:30:00Z",
"request_count": 15234,
"error_count": 42
}
]
}
Route 2: Create API Key Modal
Trigger: Click βCreate API Keyβ button
Modal Type: Centered modal with backdrop
Modal Structure
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Create API Key [X] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Name * β
β ββββββββββββββββββββββββββββββββββββββββββββββββ
β β Production Server ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β Permissions * β
β β Send emails (send_email) β
β β Read analytics (read_analytics) β
β β Manage contacts (manage_contacts) β
β β Manage campaigns (manage_campaigns) β
β β Manage templates (manage_templates) β
β β
β Rate Limit β
β 300 requests per minute (Pro plan) β
β β
β [Cancel] [Generate Key] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
Form Fields
1. Name (required)
-
Type: Text input
-
Placeholder: βe.g., Production Server, Staging Environmentβ
-
Validation: 1-50 characters, alphanumeric and spaces
-
Error: βName is requiredβ or βName must be 1-50 charactersβ
2. Permissions (required)
-
Type: Multi-select checkboxes
-
Options:
-
send_email- Send emails via API -
read_analytics- Read campaign and email analytics -
manage_contacts- Create, update, delete contacts -
manage_campaigns- Create, update, delete campaigns -
manage_templates- Create, update, delete templates -
manage_domains- Add, verify, delete domains -
read_inbox- Read unified inbox messages -
manage_webhooks- Configure webhooks
-
-
Validation: At least one permission required
-
Error: βSelect at least one permissionβ
3. Rate Limit (display only)
-
Shows tier-based rate limit
-
Starter: 60 requests/min
-
Pro: 300 requests/min
-
Enterprise: 1000 requests/min
-
Link: βUpgrade plan to increase rate limitβ
Modal Actions
Cancel Button:
-
Closes modal without creating key
-
No API call
Generate Key Button:
-
Validates form fields
-
Creates API key via API
-
Opens βAPI Key Createdβ success modal
-
Closes create modal
API Call
POST /api/v1/platform/api-keys
Request:
{
"name": "Production Server",
"permissions": ["send_email", "read_analytics", "manage_contacts"]
}
Response (201 Created):
{
"api_key": "pm_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"key_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production Server",
"permissions": ["send_email", "read_analytics", "manage_contacts"],
"rate_limit": 300,
"created_at": "2025-11-26T10:00:00Z",
"warning": "Store this key securely. It will not be shown again."
}
Route 3: API Key Created Success Modal
Trigger: After successful API key creation
Modal Type: Centered modal with backdrop (cannot close by clicking backdrop)
Modal Structure
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Γ’Ε‘Β Γ―ΒΈΒ API Key Created [X] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Store this key securely. It will not be shown β
β again. If you lose it, you'll need to β
β regenerate a new key. β
β β
β Your API Key β
β ββββββββββββββββββββββββββββββββββββββββββββββββ
β β pm_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 πΊοΈββ
β ββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β [Copy Key] [Download .env] β
β β
β Quick Start β
β ββββββββββββββββββββββββββββββββββββββββββββββββ
β β cURL Γ’βΒΌββ
β β curl -X POST https://api.penguinmails.com ββ
β β -H "Authorization: Bearer pm_live_..." ββ
β β -H "Content-Type: application/json" ββ
β β -d '{"to": "user@example.com", ...}' ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β [View Documentation] [Done] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
UI Components
1. Warning Banner
-
Icon: Γ’Ε‘Β Γ―ΒΈΒ Warning icon
-
Text: βStore this key securely. It will not be shown again.β
-
Style: Yellow background, prominent
2. API Key Display
-
Full API key value (plaintext)
-
Copy button (clipboard icon)
-
Monospace font
-
Select-all on click
3. Action Buttons
-
Copy Key: Copies API key to clipboard, shows toast
-
Download .env: Downloads file with
PENGUINMAILS_API_KEY=pm_live_...
4. Code Examples
-
Tabbed interface: cURL, Node.js, Python, PHP
-
Syntax highlighting
-
Copy button for each example
-
Pre-filled with actual API key
5. Footer Actions
-
View Documentation: Opens API docs in new tab
-
Done: Closes modal, returns to API key list
Code Examples
cURL:
curl -X POST https://api.penguinmails.com/api/v1/emails/send \
-H "Authorization: Bearer pm_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
-H "Content-Type: application/json" \
-d '{
"to": "recipient@example.com",
"subject": "Test Email",
"body": "Hello from PenguinMails API"
}'
Node.js:
const axios = require('axios');
const apiKey = 'pm_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6';
axios.post('https://api.penguinmails.com/api/v1/emails/send', {
to: 'recipient@example.com',
subject: 'Test Email',
body: 'Hello from PenguinMails API'
}, {
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
}).then(response => {
console.log('Email sent:', response.data);
}).catch(error => {
console.error('Error:', error.response.data);
});
JavaScript/Node.js:
const axios = require('axios');
const apiKey = 'pm_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6';
async function sendEmail() {
try {
const response = await axios.post(
'https://api.penguinmails.com/api/v1/emails/send',
{
to: 'recipient@example.com',
subject: 'Test Email',
body: 'Hello from PenguinMails API'
},
{
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
}
);
console.log('Email sent:', response.data);
} catch (error) {
console.error('Error:', error.response.data);
}
}
sendEmail();
Route 4: API Key Details Modal
Trigger: Click on API key row in table
Modal Type: Large centered modal with tabs
Modal Structure
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Production Server [X] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β [Overview] [Usage] [Security] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Key ID: 550e8400-e29b-41d4-a716-446655440000 β
β Masked Key: pm_live_a1b...o5p6 [Copy] β
β β
β Permissions β
β [send_email] [read_analytics] [manage_contacts]β
β β
β Rate Limit: 300 requests/min β
β Status: Active β
β β
β Created: Nov 26, 2025 at 10:00 AM β
β Last Used: 2 hours ago β
β β
β Usage Statistics β
β Total Requests: 15,234 β
β Error Count: 42 (0.28%) β
β β
β [Regenerate Key] [Revoke Key] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
Tabs
1. Overview Tab
-
Key metadata (ID, masked key, permissions, rate limit, status)
-
Created and last used timestamps
-
Usage statistics (total requests, error count)
-
Actions (Regenerate, Revoke)
2. Usage Tab
-
Requests per day chart (last 30 days)
-
Error rate trend chart
-
Top endpoints table (endpoint, request count, avg response time)
-
Geographic distribution map (if available)
3. Security Tab
-
Audit log (last 50 events)
-
IP addresses used (last 10 unique IPs)
-
Security recommendations
-
Rotation reminder (if >90 days old)
API Call
GET /api/v1/platform/api-keys/{key_id}
Response (200 OK):
{
"key_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production Server",
"masked_key": "pm_live_a1b...o5p6",
"permissions": ["send_email", "read_analytics", "manage_contacts"],
"rate_limit": 300,
"status": "active",
"created_at": "2025-11-26T10:00:00Z",
"last_used": "2025-11-26T15:30:00Z",
"request_count": 15234,
"error_count": 42,
"usage_by_day": [
{ "date": "2025-11-26", "requests": 1234, "errors": 5 },
{ "date": "2025-11-25", "requests": 2345, "errors": 8 }
],
"top_endpoints": [
{ "endpoint": "/api/v1/emails/send", "count": 12000, "avg_response_time_ms": 250 },
{ "endpoint": "/api/v1/analytics/campaigns", "count": 3234, "avg_response_time_ms": 150 }
]
}
Route 5: Regenerate API Key Confirmation Modal
Trigger: Click βRegenerateβ button
Modal Type: Small centered confirmation modal
Modal Structure
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Γ’Ε‘Β Γ―ΒΈΒ Regenerate API Key? [X] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β This will immediately revoke the old key and β
β generate a new one. Any applications using the β
β old key will stop working until you update β
β them with the new key. β
β β
β Key: Production Server β
β Current Key: pm_live_a1b...o5p6 β
β β
β [Cancel] [Regenerate Key] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
Modal Actions
Cancel Button:
-
Closes modal without regenerating
-
No API call
Regenerate Key Button:
-
Regenerates API key via API
-
Opens βAPI Key Createdβ success modal with new key
-
Closes confirmation modal
API Call
POST /api/v1/platform/api-keys/{key_id}/regenerate
Response (200 OK):
{
"api_key": "pm_live_c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8",
"key_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production Server",
"permissions": ["send_email", "read_analytics", "manage_contacts"],
"rate_limit": 300,
"created_at": "2025-11-26T16:00:00Z",
"warning": "Old key has been revoked. Update your application immediately."
}
Route 6: Revoke API Key Confirmation Modal
Trigger: Click βRevokeβ button
Modal Type: Small centered confirmation modal
Modal Structure
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Γ’Ε‘Β Γ―ΒΈΒ Revoke API Key? [X] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β This action cannot be undone. The key will be β
β permanently revoked and any applications using β
β it will stop working immediately. β
β β
β Key: Production Server β
β Current Key: pm_live_a1b...o5p6 β
β β
β [Cancel] [Revoke Key] β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
Modal Actions
Cancel Button:
-
Closes modal without revoking
-
No API call
Revoke Key Button:
-
Revokes API key via API
-
Shows success toast: βAPI key revoked successfullyβ
-
Refreshes API key list
-
Closes confirmation modal
API Call
DELETE /api/v1/platform/api-keys/{key_id}
Response (200 OK):
{
"message": "API key revoked successfully",
"key_id": "550e8400-e29b-41d4-a716-446655440000",
"revoked_at": "2025-11-26T16:30:00Z"
}
State Management
API Key List State
interface APIKeyListState {
apiKeys: APIKey[];
loading: boolean;
error: string | null;
selectedKeyId: string | null;
showCreateModal: boolean;
showDetailsModal: boolean;
showRegenerateModal: boolean;
showRevokeModal: boolean;
}
interface APIKey {
key_id: string;
name: string;
masked_key: string;
permissions: string[];
rate_limit: number;
status: 'active' | 'revoked';
created_at: string;
last_used: string | null;
request_count: number;
error_count: number;
}
Actions
// Load API keys
async function loadAPIKeys(): Promise<void> {
setState({ loading: true, error: null });
try {
const response = await fetch('/api/v1/platform/api-keys');
const data = await response.json();
setState({ apiKeys: data.api_keys, loading: false });
} catch (error) {
setState({ error: error.message, loading: false });
}
}
// Create API key
async function createAPIKey(name: string, permissions: string[]): Promise<string> {
const response = await fetch('/api/v1/platform/api-keys', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, permissions })
});
const data = await response.json();
return data.api_key; // Return plaintext key
}
// Regenerate API key
async function regenerateAPIKey(keyId: string): Promise<string> {
const response = await fetch(`/api/v1/platform/api-keys/${keyId}/regenerate`, {
method: 'POST'
});
const data = await response.json();
return data.api_key; // Return new plaintext key
}
// Revoke API key
async function revokeAPIKey(keyId: string): Promise<void> {
await fetch(`/api/v1/platform/api-keys/${keyId}`, {
method: 'DELETE'
});
await loadAPIKeys(); // Refresh list
}
Error Handling
API Errors
401 Unauthorized:
-
Redirect to login page
-
Show toast: βSession expired. Please log in again.β
403 Forbidden:
-
Show error message: βYou donβt have permission to manage API keys.β
-
Disable βCreate API Keyβ button
429 Too Many Requests:
-
Show error message: βRate limit exceeded. Please try again in a few minutes.β
-
Disable action buttons temporarily
500 Internal Server Error:
-
Show error message: βSomething went wrong. Please try again later.β
-
Log error to monitoring system
Validation Errors
Name field:
-
Empty: βName is requiredβ
-
Too long: βName must be 50 characters or lessβ
Permissions field:
- None selected: βSelect at least one permissionβ
Network Errors
Connection failed:
-
Show error message: βUnable to connect. Check your internet connection.β
-
Retry button
Timeout:
-
Show error message: βRequest timed out. Please try again.β
-
Retry button
Security Considerations
1. API Key Display
Problem: Displaying full API key after creation exposes it to shoulder surfing.
Solution:
-
Display key only once in modal
-
Require explicit user action to view (cannot close modal accidentally)
-
Warn user to store securely
-
Never display full key again (only masked)
2. Copy to Clipboard
Problem: Clipboard can be accessed by malicious browser extensions.
Solution:
-
Use secure clipboard API (
navigator.clipboard.writeText()) -
Show toast confirmation
-
Clear clipboard after 60 seconds (optional, may annoy users)
3. Download .env File
Problem: Downloaded files can be accidentally committed to version control.
Solution:
-
Include comment in .env file: β# DO NOT COMMIT THIS FILE TO VERSION CONTROLβ
-
Suggest adding
.envto.gitignore -
Link to security best practices documentation
4. Modal Security
Problem: User might close modal accidentally before copying key.
Solution:
-
Disable backdrop click to close
-
Require explicit βDoneβ button click
-
Show confirmation if user tries to close without copying
5. Regenerate Confirmation
Problem: Accidental regeneration breaks existing integrations.
Solution:
-
Require explicit confirmation
-
Show warning about immediate revocation
-
Display key name and masked value for verification
Accessibility
Keyboard Navigation
-
Tab through all interactive elements
-
Enter/Space to activate buttons
-
Escape to close modals
-
Arrow keys to navigate table rows
Screen Reader Support
-
ARIA labels for all buttons and inputs
-
ARIA live regions for toast notifications
-
ARIA descriptions for complex interactions
-
Semantic HTML (table, form, button elements)
Visual Accessibility
-
High contrast colors (WCAG AA compliant)
-
Focus indicators on all interactive elements
-
Error messages with icons and text
-
Loading states with spinners and text
Related Documentation
Planning
Implementation
Reference
-
Frontend Routing Map - Master route registry
-
Component Library - Reusable UI components
-
Design System - Design tokens and patterns
Last Updated: November 26, 2025 Document Version: 1.0 Status: PLANNED Priority: P0 - Critical
This route specification provides comprehensive UI/UX guidance for implementing the API key management interface. All implementation must reference the Tenant API Key System feature documentation for backend integration and security requirements.