Skip to main content
Admin Modules

API Dashboard

Centralized dashboard for monitoring external API services with interactive API explorer, provider visibility management, enriched provider cards, and encrypted key management

February 25, 2026

API Dashboard

The API Dashboard (v3.0.0) provides a comprehensive view of every external API service integrated into Arcturus-Prime. It shows configuration status, validates keys, pulls live usage data, provides an interactive API explorer for executing endpoints, and lets you hide unused providers.

Located at /admin/api-dashboard. Admin-only.

Features

Instructions Banner

A brief explanation at the top of the page describes how the dashboard works. Below it, a color-coded legend explains the four status dot states: green (valid key), yellow (checking), red (invalid/expired), grey (not configured). This is always visible so users do not need external documentation to interpret the page.

Summary Bar

Four counters across the top of the page:

CounterMeaning
TotalNumber of providers defined in config
ConfiguredProviders with an env var set
FreeProviders on a free tier
PaidProviders on a paid or pay-as-you-go tier

Provider Cards

Each provider renders as a card grouped by category. Cards display:

  • Status indicator (colored dot)
  • Provider name, icon, and description
  • Pricing tier badge (free / paid / payg) and endpoint count badge
  • API base URL in monospace
  • Feature tags (e.g. “90+ models”, “Streaming”, “Tool use”)
  • Rate limit info
  • Free tier details or free model list
  • Live usage data (if the provider supports it)
  • Direct links to provider website, API docs, dashboard, and billing page

Card Actions

Each card has action buttons:

ButtonIconAction
ExploreTerminalOpens the inline API Explorer panel
DocsBookOpens the provider’s API documentation (external link)
HideEye-slashHides the provider from the dashboard
ConfigureGearOpens the API key management modal

Auto-Fetch and Refresh

Usage data is fetched automatically when the page loads. A manual refresh button in the header allows re-fetching at any time. All provider checks run in parallel with an 8-second timeout per provider. Providers without usage APIs receive a key validity check instead.

Hide / Show Providers

Click the eye-slash icon on any card to hide it from the dashboard. Hidden providers are stored in Cloudflare KV (data:api-dashboard:hidden-providers) and filtered at SSR time.

A visibility dropdown in the page header (eye-slash icon with badge count) lists all hidden providers. Click “Show” next to any provider to restore it.

API Explorer

Click “Explore” on any provider card to open an inline explorer panel below the card’s section. The explorer shows all available API endpoints for that provider, grouped by category:

CategoryDescription
AccountAccount info, balances, subscription details
ModelsList available models
UsageUsage records, credit balance, generation history
ContentSearch, domains, zones, calls, emails
HealthService health checks

Each endpoint button shows:

  • HTTP method badge (GET = green, POST = blue)
  • Endpoint name and description
  • Documentation link (external)

Click any endpoint to execute it through the secure server-side proxy. The response panel shows:

  • HTTP method and URL (with any API keys stripped)
  • Status code (color-coded: green = success, red = error)
  • JSON response with syntax highlighting (keys = purple, strings = green, numbers = amber, booleans = blue, null = gray)
  • Request timing and response size
  • Copy button for the raw JSON

Provider Categories

Twelve providers ship in the default configuration across five categories:

CategoryProviderEnv VarTierFree Tier InfoLive Usage
AI / LLMOpenRouterOPENROUTER_API_KEYpaygDeepSeek R1, Llama 4, Qwen3, Nemotron free modelsYes
Google GeminiGEMINI_API_KEYfreeGemini 2.0 Flash (1500 RPD), 1M contextNo
GroqGROQ_API_KEYfreeLlama 3.3 70B, Whisper Large v3 (30 RPM)No
NVIDIA NIMNVIDIA_NIM_API_KEYfree1000 free API calls on signupNo
AnthropicANTHROPIC_API_KEYpaidNo
OpenAIOPENAI_API_KEYpaidNo
VoiceElevenLabsELEVENLABS_API_KEYfree10K chars/moYes
SearchBrave SearchBRAVE_API_KEYfree2K queries/moNo
PerplexityPERPLEXITY_API_KEYpaidNo
CommunicationTwilioTWILIO_ACCOUNT_SIDpaygYes
ResendRESEND_API_KEYfree3K emails/mo, 100/dayNo
InfrastructureCloudflareCF_API_TOKENfreeWorkers 100K req/day, Pages 500 builds/moNo

Twilio requires three env vars: TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, and TWILIO_FROM_NUMBER. Cloudflare also uses CF_ACCOUNT_ID.

Live Usage Data

Three providers return real-time usage information from their APIs. All others perform a key validity check only (HTTP request to the provider’s models or verify endpoint).

OpenRouter

Calls two endpoints in parallel:

  • GET /api/v1/auth/key — returns limit, usage, rate limits, free tier status
  • GET /api/v1/credits — returns total_credits and total_usage (requires management key)
FieldSourceDescription
credits/creditsAccount balance (totalCredits - totalUsage)
totalCredits/creditsTotal credits purchased
totalUsage/creditsTotal credits spent
limitRemaining/auth/keySpending cap remainder (limit - usage)
usage/auth/keyUsage against spending limit
limit/auth/keySpending cap
isFreeTier/auth/keyWhether the key is on the free tier
rateLimitRequests/auth/keyRequests per interval
rateLimitInterval/auth/keyRate limit window

Note: credits (balance) and limitRemaining are different values. Credits is your actual deposited balance from /api/v1/credits. Limit remaining is how much of your spending cap is left from /api/v1/auth/key. The /api/v1/credits endpoint requires a management API key — if a regular key is used, the balance fields will be unavailable.

ElevenLabs

Calls GET /v1/user/subscription with the xi-api-key header.

FieldDescription
tierSubscription tier name
characterCountCharacters used this period
characterLimitCharacter quota for the period
voiceCountVoice slot limit
nextResetUnixUnix timestamp of next quota reset

The dashboard renders a progress bar for character usage against the limit.

Twilio

Calls the Account and Balance REST APIs with Basic auth.

FieldDescription
statusAccount status (active, suspended, closed)
typeAccount type
friendlyNameAccount display name
balanceCurrent balance amount
currencyBalance currency code

Custom Providers

Admins can add custom API providers directly from the dashboard UI without editing config files or redeploying.

Adding a Custom Provider

Click the + button in the dashboard header. Fill in the modal form:

FieldRequiredDescription
Provider NameYesDisplay name (e.g. “Replicate”)
Env Var NameYesEnvironment variable holding the API key
CategoryYesWhich section the card appears in
TierNoFree, Paid, or Pay-as-you-go
DescriptionNoShort description
Pricing NoteNoPricing info shown on the card
Dashboard URLNoLink to provider’s management console
Billing URLNoLink to provider’s billing page
IconNoFont Awesome class (defaults to fa-plug)
Validation URLNoURL to check key validity (hit with the key as auth)
Auth TypeNoBearer Token or X-API-Key header

Storage

Custom providers are stored in Cloudflare KV at key data:api-dashboard:custom-providers. The page fetches them at SSR time and merges with the static config. The API usage endpoint also checks custom providers alongside built-ins.

Editing and Deleting

Custom provider cards show edit (pencil) and delete (trash) buttons. Click edit to modify any field. Delete requires confirmation. Built-in providers cannot be edited or deleted from the UI — modify config.local.json instead.

Limitations

Custom providers only get generic key validity checks (hit a URL, check for HTTP 200). They do not get live usage data like OpenRouter credits or ElevenLabs character counts. Provider IDs cannot collide with built-in provider IDs.

Configuration

Provider definitions live in JSON config files in the module repo root.

config.default.json

Ships with the module. Contains all 12 default providers with their metadata: name, description, icon, category, tier, env var(s), free tier info, pricing notes, and dashboard/billing URLs. Do not edit this file — it gets overwritten on module updates.

config.local.json

Created automatically by install.sh as a copy of config.default.json. This file is gitignored. Edit it to:

  • Remove providers you do not use
  • Override descriptions, icons, or pricing notes
  • Change category assignments

The dashboard reads config.local.json if it exists, falling back to config.default.json. The install script copies the chosen config into Arcturus-Prime as a JSON file that gets bundled by Vite at build time. For adding new providers at runtime, use the Custom Providers feature instead.

Installation

The API Dashboard lives in a standalone module repo (Arcturus-Prime-module-api-dashboard), separate from the main Arcturus-Prime codebase. The installer copies files into Arcturus-Prime because Astro/Vite does not follow symlinks for relative imports.

Install

cd ~/Development/Arcturus-Prime-module-api-dashboard
./install.sh

This copies five files into Arcturus-Prime:

SourceDestinationPurpose
src/pages/admin/api-dashboard.astroSame path in Arcturus-PrimeDashboard page
src/pages/admin/_api-dashboard-config.jsonSame path in Arcturus-PrimeProvider config (Vite JSON import)
src/config/modules/api-dashboard.tsSame path in Arcturus-PrimeModule registration
src/pages/api/admin/api-usage.tsSame path in Arcturus-PrimeStatus check endpoint
src/pages/api/admin/api-dashboard-providers.tsSame path in Arcturus-PrimeCustom provider CRUD endpoint

The config file is copied from config.local.json (if it exists) or config.default.json. The underscore prefix ensures Astro does not create a route for it. The .astro page imports it as a standard JSON module, which Vite bundles at build time — this ensures it works on Cloudflare Workers where there is no filesystem at runtime.

The install script also creates config.local.json from config.default.json if it does not already exist. Run npm run blueprint afterward to update the site blueprint.

Uninstall

cd ~/Development/Arcturus-Prime-module-api-dashboard
./uninstall.sh

Removes the five copied files from Arcturus-Prime. Run npm run blueprint afterward.

Updating

Re-run install.sh after editing module source files or config. It overwrites the copies in Arcturus-Prime.

Status Indicators

Each provider card shows a colored status dot:

ColorMeaning
GreenKey is configured and validated successfully
YellowKey is configured but has not been checked (or check was inconclusive)
RedKey is configured but validation failed (invalid key or provider error)
GreyNo env var set — provider is not configured

Security

The API endpoint requires Cloudflare Access admin authentication via validateAdmin() — the same pattern used by all other admin API routes. Unauthenticated requests receive a 401 response. No API keys or secrets are ever included in the response — only configuration status, key validity booleans, and usage metrics.

The dashboard page itself is served under /admin/ which is blocked by middleware for non-Arcturus-Prime.com hosts, and protected by Cloudflare Access in production.

API Endpoint

GET /api/admin/api-usage

Returns the status of all configured providers. Requires Cloudflare Access admin authentication (validateAdmin). Returns 401 if not authenticated.

Response:

{
  "providers": [
    {
      "id": "openrouter",
      "configured": true,
      "valid": true,
      "usage": {
        "credits": 9.25,
        "totalCredits": 12.50,
        "totalUsage": 3.25,
        "limitRemaining": 46.75,
        "usage": 3.25,
        "limit": 50,
        "isFreeTier": false,
        "rateLimitRequests": 200,
        "rateLimitInterval": "10s"
      }
    },
    {
      "id": "gemini",
      "configured": true,
      "valid": true
    },
    {
      "id": "anthropic",
      "configured": false,
      "valid": null
    }
  ],
  "fetchedAt": "2026-02-25T18:30:00.000Z"
}

Each provider object contains:

FieldTypeDescription
idstringProvider identifier (matches config key)
configuredbooleanWhether the env var is set
validboolean or nullKey validity (null if unchecked or errored)
usageobject (optional)Live usage data (only for providers with usage APIs)
errorstring (optional)Error message if the check failed

All provider checks run via Promise.allSettled — one failing provider does not block the others. Each check has an 8-second timeout. Custom providers from KV are checked alongside built-in providers.

GET /api/admin/api-dashboard-providers

Returns all custom providers stored in KV. Requires admin auth.

POST /api/admin/api-dashboard-providers

Add or update a custom provider. Body must be JSON with at minimum id, name, envVar, and category. Returns { ok: true, id } on success. Returns 400 if validation fails (e.g. id collides with a built-in provider).

DELETE /api/admin/api-dashboard-providers?id=xxx

Remove a custom provider by id. Returns { ok: true } on success, 404 if not found.

API Key Management

API keys can be configured directly from the dashboard UI without editing Worker Secrets or redeploying.

How It Works

Each provider card has a Configure button (gear icon). Clicking it opens a key configuration modal showing:

  • Current key status (configured via KV, Worker Secret, or not configured)
  • Masked current value (prefix + last 4 chars)
  • Password input for entering a new key value
  • Save button that encrypts and stores the key, then validates it against the provider API

Multi-Key Providers

Some providers require multiple credentials:

ProviderKeys
TwilioTWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN + TWILIO_FROM_NUMBER
CloudflareCF_API_TOKEN + CF_ACCOUNT_ID

The modal renders a separate input field for each required key.

Encryption

Keys are encrypted at rest using AES-256-GCM via the Web Crypto API.

DetailValue
AlgorithmAES-256-GCM
Key sourceAPI_KEYS_ENCRYPTION_KEY env var (64-char hex = 32 bytes)
IV12-byte random per encryption
Storage formatbase64(iv || ciphertext)
KV keydata:api-keys
Generate keyopenssl rand -hex 32

The encryption key itself must be set as a Worker Secret — it cannot be stored in KV (circular dependency).

Key Resolution (getEnv Fallback Chain)

When any part of Arcturus-Prime calls getEnv("SOME_API_KEY"), the resolution order is:

  1. KV-stored keys (user-managed via admin UI) — highest priority
  2. Cloudflare Worker Secrets (set via wrangler secret put)
  3. process.env (dev mode, loaded from .env by Vite)

UI-managed keys take precedence over Worker Secrets. This allows overriding secrets without redeployment.

The KV keys are decrypted once per Worker isolate via loadKvApiKeys() (called from middleware) and cached in memory for the isolate’s lifetime.

Validation on Save

When a key is saved, the API endpoint validates it against the provider’s API before responding. Validators exist for:

ProviderValidation Endpoint
OpenRouterGET /api/v1/auth/key
GroqGET /openai/v1/models
NVIDIA NIMGET /v1/models
AnthropicGET /v1/models
OpenAIGET /v1/models
Brave SearchGET /res/v1/web/search
ResendGET /domains

Each validation has an 8-second timeout. Providers without a validator return valid: null.

Setup Guide

A setup guide panel appears on the dashboard when API_KEYS_ENCRYPTION_KEY is not configured. It warns that key management requires the encryption key and provides the openssl rand -hex 32 command.

API Endpoints (Key Management)

GET /api/admin/api-keys

Returns masked key status for all known env vars. Requires admin auth.

Response:

{
  "keys": {
    "OPENROUTER_API_KEY": { "masked": "sk-or-...x1y2", "source": "kv" },
    "GEMINI_API_KEY": { "masked": "AIza...abcd", "source": "env" },
    "ANTHROPIC_API_KEY": { "masked": null, "source": null }
  },
  "encryptionConfigured": true
}
FieldDescription
maskedPrefix + last 4 chars, or null if not configured
source"kv" (UI-managed), "env" (Worker Secret), or null
encryptionConfiguredWhether API_KEYS_ENCRYPTION_KEY is set

POST /api/admin/api-keys

Save a key (encrypted in KV). Validates against provider API after saving.

Request body: { "envVar": "OPENROUTER_API_KEY", "value": "sk-or-..." }

Response: { "ok": true, "valid": true, "masked": "sk-or-...x1y2" }

StatusCondition
200Key saved (check valid field for validation result)
400Missing fields or encryption key not configured
503KV unavailable

DELETE /api/admin/api-keys?envVar=OPENROUTER_API_KEY

Remove a key from KV storage. Falls back to Worker Secret if one exists.

StatusCondition
200{ ok: true }
400Missing envVar or encryption key not configured
404Key not found in KV

Source Files (Key Management)

FilePurpose
src/lib/key-encryption.tsAES-256-GCM encrypt/decrypt via Web Crypto API
src/pages/api/admin/api-keys.tsGET status, POST save, DELETE remove
src/lib/runtime-env.tsgetEnv() fallback chain, loadKvApiKeys(), getEnvDirect()
src/middleware.tsCalls loadKvApiKeys() after setRuntimeEnv() on every request
src/pages/admin/_api-dashboard-config.jsonProvider definitions with signupUrl, instructions per provider

API Explorer

How It Works

The API Explorer lets you execute any available API endpoint for a provider directly from the dashboard. Click “Explore” on a card to open an inline explorer panel.

Requests are proxied through the server (/api/admin/api-proxy) so credentials are never exposed to the browser. Only endpoints defined in the static config’s endpointMap can be executed (whitelist enforcement).

Endpoint Map

28 endpoints are defined across 12 providers in the config’s endpointMap:

ProviderEndpointsCategories
OpenRouterList Models, Key Info, Credit Balancemodels, account, usage
GeminiList Modelsmodels
GroqList Modelsmodels
NVIDIA NIMList Models, Health Checkmodels, health
AnthropicList Modelsmodels
OpenAIList Modelsmodels
ElevenLabsSubscription Info, List Voices, Generation Historyaccount, content, usage
BraveWeb Search Testcontent
Perplexity(none)
TwilioAccount Info, Balance, Usage Records, Recent Callsaccount, usage, content
ResendList Domains, Recent Emailsaccount, content
CloudflareVerify Token, List Zones, List Accountsaccount, content

Each endpoint definition includes: id, method, path, baseUrl, name, category, description, docsUrl, and optional pathParams and bodyTemplate.

Auth Patterns

The proxy dispatches authentication based on the provider’s authPatterns config entry:

Auth TypeHow It WorksProviders
bearerAuthorization: Bearer <key>OpenRouter, Groq, NVIDIA, OpenAI, Perplexity, Resend, Cloudflare
x-api-keyCustom header nameAnthropic (x-api-key + anthropic-version: 2023-06-01)
custom-headerArbitrary header nameElevenLabs (xi-api-key), Brave (X-Subscription-Token)
query-paramAppends ?key=<value> to URLGemini
basicHTTP Basic auth (user:password)Twilio (SID:AuthToken)

Path Parameters

Some endpoints have dynamic path segments (e.g. Twilio’s /2010-04-01/Accounts/{AccountSid}/Balance.json). Path parameters use two sources:

  • env:VAR_NAME — auto-substituted from server environment (e.g. env:TWILIO_ACCOUNT_SID)
  • input:key — would prompt the user (not yet implemented in the UI)

POST /api/admin/api-proxy

Server-side API proxy. POST-only, requires admin auth.

Request body:

{
  "endpointId": "openrouter-models",
  "pathValues": {},
  "requestBody": null
}

Response:

{
  "ok": true,
  "status": 200,
  "statusText": "OK",
  "data": { "...parsed JSON response..." },
  "truncated": false,
  "endpoint": {
    "id": "openrouter-models",
    "method": "GET",
    "url": "https://openrouter.ai/api/v1/models"
  },
  "fetchedAt": "2026-02-27T23:00:00.000Z"
}
FieldDescription
okWhether the upstream API returned a 2xx status
statusHTTP status code from upstream
dataParsed JSON response (null if not parseable)
rawRaw text response (only if JSON parsing failed)
truncatedWhether the response was truncated at 512KB
endpointEcho of endpoint ID, method, and sanitized URL

Security

  • Only whitelisted endpoints from the static config can be proxied
  • Credentials are injected server-side and never sent to the browser
  • API keys are stripped from URLs in the response (sanitizeUrl())
  • POST-only to prevent CSRF via GET requests
  • 512KB response cap prevents memory issues
  • 15-second timeout per request
  • Requires validateAdmin() authentication

Provider Visibility

GET /api/admin/api-hidden-providers

Returns the list of hidden provider IDs. Requires admin auth.

Response: { "hidden": ["perplexity", "anthropic"] }

POST /api/admin/api-hidden-providers

Toggle a provider’s visibility. Requires admin auth.

Request body: { "id": "perplexity", "hidden": true }

Response: { "ok": true, "hidden": ["perplexity", "anthropic"] }

Hidden providers are stored in KV at data:api-dashboard:hidden-providers (JSON array). They are filtered out at SSR time. The visibility dropdown in the page header lists hidden providers and allows restoring them.

All Source Files

FilePurpose
src/pages/admin/api-dashboard.astroMain dashboard page
src/pages/admin/_api-dashboard-config.jsonProvider definitions, endpoint map, auth patterns
src/pages/api/admin/api-proxy.tsServer-side API proxy (whitelist, multi-auth)
src/pages/api/admin/api-hidden-providers.tsKV-backed hide/unhide toggle
src/pages/api/admin/api-usage.tsProvider status and live usage data
src/pages/api/admin/api-dashboard-providers.tsCustom provider CRUD
src/pages/api/admin/api-keys.tsEncrypted key management
src/lib/key-encryption.tsAES-256-GCM encrypt/decrypt
src/lib/runtime-env.tsgetEnv() fallback chain, loadKvApiKeys()
src/config/modules/api-dashboard.tsModule manifest (v3.0.0)
adminapimonitoringprovidersusagebillingmoduleexplorer