/** * Developer Dashboard — API Keys & Webhooks (v0.102) * Manages API keys and links to Swagger docs. Webhooks at /webhooks. */ import React, { useState, useEffect } from 'react'; import { Card, CardContent } from '../ui/card'; import { Button } from '../ui/button'; import { EmptyState } from '../ui/empty-state'; import { SwaggerUIDoc } from './SwaggerUI'; import { CreateAPIKeyModal } from './modals/CreateAPIKeyModal'; import { ConfirmationDialog } from '../ui/confirmation-dialog'; import { ExternalLink, Key, Plus, Trash2, Loader2, } from 'lucide-react'; import { developerService, type ApiKey } from '@/services/developerService'; import { useToast } from '@/components/feedback/ToastProvider'; export const DeveloperDashboardView: React.FC = () => { const { addToast } = useToast(); const [keys, setKeys] = useState([]); const [loading, setLoading] = useState(true); const [showCreateModal, setShowCreateModal] = useState(false); const [revokeId, setRevokeId] = useState(null); const fetchKeys = async () => { setLoading(true); try { const list = await developerService.listKeys(); setKeys(list); } catch (e) { addToast('Failed to load API keys', 'error'); setKeys([]); } finally { setLoading(false); } }; useEffect(() => { void fetchKeys(); }, []); const handleCreate = async (data: { name: string; scopes: string[]; }): Promise<{ key?: string; id: string; name: string; prefix: string }> => { const created = await developerService.createKey(data); await fetchKeys(); return { key: created.key, id: created.id, name: created.name, prefix: created.prefix, }; }; const handleRevoke = async (id: string) => { try { await developerService.deleteKey(id); await fetchKeys(); addToast('API key revoked', 'success'); } catch { addToast('Failed to revoke API key', 'error'); } finally { setRevokeId(null); } }; return (

DEVELOPER PORTAL

API Keys & Webhooks — Manage your API keys and explore the docs.

API Keys

{loading ? (
) : keys.length === 0 ? ( } title="No API keys yet" description="Create an API key to authenticate your apps and scripts. Use the X-API-Key header or Authorization: Bearer <key>." variant="card" /> ) : (
{keys.map((k) => (
{k.name}
{k.prefix}
Created {k.created} {k.lastUsed !== 'Never' && ` · Last used ${k.lastUsed}`}
{k.scopes.length > 0 && (
{k.scopes.map((s) => ( {s} ))}
)}
))}
)}
{showCreateModal && ( setShowCreateModal(false)} onCreate={handleCreate} /> )} setRevokeId(null)} onConfirm={() => revokeId && handleRevoke(revokeId)} title="Revoke API key" description="This will immediately invalidate the key. Any apps using it will stop working." confirmLabel="Revoke" variant="destructive" />
); };