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


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 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”

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)


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Òő ï¸ 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

  • 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


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 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


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Òő ï¸ 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]   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

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


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Òő ï¸ 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]  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

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 .env to .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


Planning

Implementation

Reference


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.