EgressView exposes a private administration API for its web UI and local automation. The API is not yet a versioned public compatibility contract; review release notes before upgrading an external integration.
API paths are rooted at /api, even when the web UI is served below a subpath. Protected requests accept the legacy X-Admin-Token, a scoped API identity token in the same header, or an HttpOnly browser session cookie. Cookie-authenticated mutations also require the matching X-CSRF-Token.
Scoped API identities are managed through GET / POST /api/auth/api-identities and POST /api/auth/api-identities/:id/revoke, all requiring auth.admin. Creation requires a label, a non-empty permission list, and expiresInMs between one minute and one year. The plaintext egv_... token is returned only in the 201 creation response; only its SHA-256 hash is stored. Identity-management responses use Cache-Control: no-store.
GET /api/auth/api-identities/self returns only the currently authenticated
scoped identity and requires network.read; browser sessions and the legacy
admin token are rejected. The remote MCP server uses it to fail closed unless
its internal service identity grants exactly network.read and notes.write.
export EGRESSVIEW_URL='https://egressview.example.net'
export EGRESSVIEW_TOKEN='replace-with-your-admin-token'
curl --fail-with-body \
-H "X-Admin-Token: $EGRESSVIEW_TOKEN" \
"$EGRESSVIEW_URL/api/status"Use HTTPS or a trusted VPN when crossing a network boundary. Never put a token in a URL, log, or source file. The JSON request-body limit is 64 KB.
POST /api/auth/login is public and exchanges the UI password for a revocable session token. A password may contain at most 256 characters. Five failed attempts from one client trigger a five-minute lockout within the ten-minute tracking window.
curl --fail-with-body \
-H 'Content-Type: application/json' \
-d '{"password":"replace-with-your-password"}' \
"$EGRESSVIEW_URL/api/auth/login"{"success":true,"token":"session-token","expiresAt":1784304000000}POST /api/admin/verify is also public and verifies a token supplied in the request body. Authentication status/method discovery and the OIDC redirect/callback are public. The detail-free /healthz and /readyz checks are public; all other endpoints are protected.
- Timestamps are Unix epoch milliseconds. Empty
fromandtovalues mean an open time range unless an endpoint says otherwise. - Every response includes
X-Request-Id. A caller ID matching[A-Za-z0-9][A-Za-z0-9._:-]{0,63}is preserved; a missing or unsafe value is replaced with a generated UUID. The same safe ID correlates request, asynchronous, slow-request, and error logs. Query strings are not included in HTTP completion logs. - Every endpoint-bearing route module validates request bodies, query strings, and path parameters at a strict Zod boundary. Unknown fields, arrays or objects supplied for scalar parameters, and values over the documented limits return
400before application state is changed. - Successful JSON responses use
application/json; errors normally use{ "error": "message" }. - Common status codes are
400for invalid input,401for invalid authentication,404for a missing resource,413for an oversized upload,500for an internal or persistence failure,502for router detection failure, and503while authentication is not initialized. - Router passwords, enable passwords, host fingerprints, and admin tokens are never returned by router-list APIs.
- MCP is a separate protocol. See the MCP setup guide instead of using these REST paths through an MCP client.
GET /api/connections
| Query | Description |
|---|---|
from, to |
Optional epoch-millisecond range. |
limit, offset |
Pagination. limit is clamped to 1,000. The unpaged compatibility form is capped at 50,000 rows and returns truncated; the graph uses /api/connections/summary. |
sort |
lastSeen, src, dst, dport, proto, country, or org; default lastSeen. |
sortDir |
asc or desc; default desc. |
fSrc, fDst, fDport, fProto, fCountry, fOrg |
Server-side column filters. Append Mode with contains, startsWith, endsWith, or exact. |
fSrcMac |
Exact source-MAC filter. |
fThreat |
safe, warn, or danger. |
curl --fail-with-body \
-H "X-Admin-Token: $EGRESSVIEW_TOKEN" \
"$EGRESSVIEW_URL/api/connections?from=1784217600000&limit=100&sort=lastSeen&sortDir=desc"The response contains connections, total, limit, offset, and serverTime. Each connection can include source-device metadata, destination enrichment, firstSeen, lastSeen, observedBy router IDs, a compatibility source value derived from those routers, and an optional threat object.
GET /api/connections/summaryacceptsfrom,to, optionalsrc, andbucketsfrom 1 to 240 (default 60).GET /api/connections/new-nodesreturns newly observed source and destination nodes for a time range.GET /api/connections/threat-connectionsacceptsconfidence=low|high|alland alimitcapped at 200.GET /api/connections/threat-countsreturnssafe,warn, anddangercounts and accepts the standard server-side filters.GET /api/connections/memoryreports the in-memory working-set statistics.
GET /api/connections/export requires format=csv|json and from; to defaults to the current time.
curl --fail-with-body \
-H "X-Admin-Token: $EGRESSVIEW_TOKEN" \
"$EGRESSVIEW_URL/api/connections/export?format=csv&from=1784217600000" \
-o connections.csvExports stream in pages of 1,000, stop at 50,000 rows, and time out after 60 seconds. Inspect X-Export-Total, X-Export-Count, and X-Export-Truncated. CSV is UTF-8 with a BOM and applies spreadsheet-formula injection protection. JSON returns meta and connections.
EgressView supports up to 10 enabled or disabled Yamaha/Cisco records.
GET /api/routersreturns safe public fields and runtime status.POST /api/routers/detecttests an unsaved router definition and returns detected LAN/NAT information or502diagnostics.POST /api/routerscreates a router and returns201.PUT /api/routers/:idupdates a router; itskindand stable router ID cannot be changed.DELETE /api/routers/:idremoves it from active configuration while historical observations remain attributable to its tombstoned ID.
Create/detect bodies use kind (yamaha or cisco), displayName, ip, user, pass, and enabled. Yamaha also uses nat; Cisco may use enablePass. Omitting a password during update preserves the stored value.
GET /api/devicesacceptsincludeArchived=1and returns identity, status, IPv6 addresses, and notes.GET /api/devices/merge-candidatesacceptsstatus=pending|approved|rejected|all.POST /api/devices/mergeuses{ "keepId": "...", "dropId": "..." }.POST /api/devices/rejectuses{ "id": "..." }.POST /api/devices/archiveandPOST /api/devices/unarchiveuse{ "deviceId": "..." }.GET /api/notesqueries saved notes.POST /api/noteswrites a note of at most 500 characters.POST /api/notes/draftproduces a draft through the configured assistant integration.
GET /api/backup/listlists normal generations, retention settings, normal/pre-migration inventory, disk headroom, and next-migration readiness. Inventory entries are lightweight and reportintegrity: "unchecked"until a verified cleanup preview runs.POST /api/backup/createcreates and verifies a consistent SQLite snapshot.GET /api/backup/download/:namedownloads a named generation.POST /api/backup/restoreuses{ "name": "..." }.POST /api/backup/uploadaccepts a raw SQLite file body up to 100 MB, not multipart form data.POST /api/backup/configaccepts positiveintervalHours,maxGenerations(minimum 2), non-negativemaxBackupBytes(0disables the storage cap), and booleanautoPrune. Auto-prune defaults to off.POST /api/backup/pruneaccepts{ "execute": false }for a verified dry-run or{ "execute": true }for confirmed cleanup and returns202with a worker job. Integrity checks run outside the main event loop, so collection and HTTP remain responsive. Only one cleanup job may run; another request receives409.GET /api/backup/prune/:jobIdreturns job status (running,cancelling,timing_out,completed,cancelled,timed_out, orfailed), progress, and the completed plan/result.DELETE /api/backup/prune/:jobIdrequests safe cancellation. Cleanup always keeps two normal generations and the latest verified migration generation; corrupt, unverified, changed, and temporary files are never deleted.
GET /healthzis an unauthenticated, cache-disabled liveness check and returns only{ "status": "ok" }when the Node.js event loop can respond.GET /readyzis an unauthenticated, cache-disabled readiness check. It returns503with{ "status": "not_ready" }until configuration and DB bootstrap complete, then200with{ "status": "ready" }. It exposes no router, database, or credential details.
AI insights always shows locally calculated facts. Only after an explicit user action, it sends aggregates — including destination IPs, hostnames, device names, and MAC addresses — to the configured AI provider. Credentials such as passwords are never sent.
GET /api/config/aireturns the selected provider, model IDs, Ollama endpoint, AWSregion, key-set/consent flags, andselectedModelPricing. API key values are never returned.POST /api/config/aiacceptsprovider(disabled,ollama,anthropic,openai, orbedrock), provider-keyedmodels,ollamaEndpoint, a Bedrockregion, optional cloudkeys, andclearKeys. Any externally transmitting provider (anthropic,openai,bedrock) requires provider-specificcloudConsent: true. Bedrock stores no key and delegates authentication to the AWS SDK default credential chain;models.bedrockaccepts a foundation model ID, a cross-region inference profile ID (global/us/eu/apac/jp/au), or an ARN (up to 400 chars). An optionalguardrail({ enabled, id, version }) attaches a Bedrock Guardrail, passed to Converse viaguardrailConfigwhen enabled (requiresbedrock:ApplyGuardrail); note that Guardrails do not guarantee in-Japan processing (seedocs/setup-bedrock.md).POST /api/ai/modelsaccepts a Bedrockregionand retrieves at most 200 text-generation model/inference-profile IDs without running inference. The response addsmodelPricingcoverage while retaining the stringmodelsarray. Specialized image, audio, embedding, and similar IDs are omitted from the picker, but manual model entry remains available as a fallback.POST /api/ai/pricing/checkaccepts a provider and model ID and reports whether the versioned catalog has a matching standard token rate. It does not contact the provider or invoke a model.POST /api/ai/guardrailsaccepts a Bedrockregionand lists that region's Guardrails (id, name, and versions) without running inference. Fail-open: a missingbedrock:ListGuardrailspermission returns an empty list so the settings UI falls back to manual guardrail entry.POST /api/ai/testaccepts an empty JSON object. Fetch-based providers retrieve at most 200 model IDs (10-second timeout, 1 MB limit). Bedrock runs fail-open model discovery and additionally sends a short fixed string via Converse to verifybedrock:InvokeModelpermission (no network, device, or threat data is sent).GET /api/ai/factsrequiresfromand acceptstoas epoch milliseconds. It returns current and immediately preceding equal-period counts for connections, devices, destinations, and threat levels, plus credential-free router collection status. The range is capped at 14 days and no data is sent to an AI provider.POST /api/ai/analyzeacceptsfromand optionalto, then sends connection aggregates plus a bounded device inventory (up to 30 activity-prioritized devices) and ASUS network-node summaries (up to 10 nodes and 5 sample devices per node). Fields can include destination/source IPs, hostnames, device names, MACs, vendors, IPv6, first/last seen, source, status, and counts. Credentials, device notes, archived devices, router/node management IPs, and raw logs are excluded. Externally transmitting providers (Anthropic/OpenAI/Bedrock) require both saved consent andcloudConsentConfirmed: trueon each request. The range is capped at 14 days, timeout is 30 seconds, and only one analysis may run server-wide.GET /api/ai/usage/monthlyaccepts the browsertimezoneOffsetin minutes and returns current/previous local-calendar-month request and token totals. Itspricingobject includes the catalog version, effective date, and source URLs.pricedTokens,unpricedTokens, and groupedunpricedModelsmake clear when estimated USD is only a partial total. Successful Ollama, Anthropic, OpenAI, and Bedrock calls are appended to v7 SQLite with the provider/model and the price-table version and rates used at invocation time, so later catalog updates do not recalculate prior months.unknownPriceRequestsand provider responses without usage (usageMissingRequests) remain distinct and are never mislabeled as USD 0; add-on charges such as Bedrock Guardrails are excluded. Conversation retrieval joinsusageInputTokens,usageOutputTokens,usageTotalTokens,estimatedCostUsd, andpricingVersionfrom the same request onto assistant messages; history created before usage recording keeps provider/model with null usage instead of inferred values. The UI uses$in English and explicitUSDnotation in Japanese without currency conversion.GET /api/ai/pricing/diagnosticsacceptstimezoneOffsetand returns the selected model's catalog status plus grouped unpriced models for the current and previous local month. It exposes model IDs and usage totals, never API keys or prompt/network contents.POST /api/ai/chataccepts amessageof at most 4,000 characters, a range, and optionalconversationIdandrequestId. It appends the user row to v6 SQLite before calling AI, then appends an assistant row on success or a body-free failure row. The samerequestId + roleis never duplicated.GET /api/ai/conversationsreturns at most 100 conversations plus stored counts and body bytes.GET /api/ai/conversations/:idreturns at most 500 messages in append order, whileDELETE /api/ai/conversations/:idis the only explicit conversation deletion path. Restart and configuration changes never update or truncate existing rows.
Provider configuration is disabled by default. Anthropic and OpenAI use their fixed official API endpoints; only Ollama accepts a custom HTTP(S) endpoint. Bedrock uses a region and the Converse API, delegating authentication to the AWS SDK default credential chain (no key entry or storage). Bedrock support ships as a standard dependency (@aws-sdk/client-bedrock-runtime and @aws-sdk/client-bedrock); no extra install. See docs/setup-bedrock.md.
Restore is fail-closed: EgressView validates the source, confirms a safety backup, restores and reopens all database users, verifies the result, and rolls back on failure. Active browser sessions are revoked after a successful restore.
All 91 implemented HTTP endpoints are listed below. Public means no token is required. Protected endpoints accept the legacy or scoped X-Admin-Token credential or the browser's HttpOnly session cookie; cookie-authenticated mutations additionally require X-CSRF-Token.
| Area | Method and path | Access |
|---|---|---|
| Authentication | POST /api/auth/login |
Public |
| Authentication | POST /api/admin/verify |
Public |
| Authentication | GET /api/auth/status |
Public |
| Authentication | GET /api/auth/methods |
Public |
| Authentication | GET /api/auth/oidc/start |
Public |
| Authentication | GET /api/auth/oidc/callback |
Public |
| Authentication | POST /api/auth/logout |
Protected |
| Authentication | GET /api/auth/sessions |
Protected |
| Authentication | POST /api/auth/sessions/:id/revoke |
Protected |
| Authentication | POST /api/auth/sessions/revoke-all |
Protected |
| Authentication | POST /api/auth/change-password |
Protected |
| Authentication | POST /api/admin/regenerate-token |
Protected |
| Authentication | GET /api/auth/security-config |
Protected |
| Authentication | POST /api/auth/security-config |
Protected |
| Authentication | POST /api/auth/oidc/test |
Protected |
| Authentication | GET /api/auth/api-identities |
Protected |
| Authentication | POST /api/auth/api-identities |
Protected |
| Authentication | POST /api/auth/api-identities/:id/revoke |
Protected |
| Authentication | GET /api/auth/audit-events |
Protected |
| Router setup | POST /api/nonce |
Protected |
| Router setup | POST /api/yamaha/detect |
Protected |
| Router setup | POST /api/cisco/detect |
Protected |
| Router setup | POST /api/login |
Protected, legacy setup flow |
| Routers | GET /api/routers |
Protected |
| Routers | POST /api/routers/detect |
Protected |
| Routers | POST /api/routers |
Protected |
| Routers | PUT /api/routers/:id |
Protected |
| Routers | DELETE /api/routers/:id |
Protected |
| Connections | GET /api/connections |
Protected |
| Connections | GET /api/connections/memory |
Protected |
| Connections | GET /api/connections/summary |
Protected |
| Connections | GET /api/connections/new-nodes |
Protected |
| Connections | GET /api/connections/threat-connections |
Protected |
| Connections | GET /api/connections/threat-counts |
Protected |
| Connections | GET /api/connections/export |
Protected |
| Devices | GET /api/devices |
Protected |
| Devices | GET /api/devices/merge-candidates |
Protected |
| Devices | POST /api/devices/merge |
Protected |
| Devices | POST /api/devices/reject |
Protected |
| Devices | POST /api/devices/archive |
Protected |
| Devices | POST /api/devices/unarchive |
Protected |
| Notes | GET /api/notes |
Protected |
| Notes | POST /api/notes |
Protected |
| Notes | POST /api/notes/draft |
Protected |
| Backup | GET /api/backup/list |
Protected |
| Backup | POST /api/backup/create |
Protected |
| Backup | GET /api/backup/download/:name |
Protected |
| Backup | POST /api/backup/restore |
Protected |
| Backup | POST /api/backup/upload |
Protected |
| Backup | POST /api/backup/config |
Protected |
| Backup | POST /api/backup/prune |
Protected |
| Backup | GET /api/backup/prune/:jobId |
Protected |
| Backup | DELETE /api/backup/prune/:jobId |
Protected |
| Process health | GET /healthz |
Public; minimal liveness only |
| Process health | GET /readyz |
Public; minimal readiness only |
| General configuration | GET /api/status |
Protected |
| General configuration | POST /api/config/general |
Protected |
| Data sources | GET /api/config/datasources |
Protected |
| Data sources | POST /api/config/datasources |
Protected |
| Slack | GET /api/config/slack |
Protected |
| Slack | POST /api/config/slack |
Protected |
| Notifications | GET /api/config/detection-notifications |
Protected |
| Notifications | POST /api/config/detection-notifications |
Protected |
| Manual threat investigation | GET /api/config/manual-threat |
Protected; returns key-set flags, never key values |
| Manual threat investigation | POST /api/config/manual-threat |
Protected; saves API keys, cache, and provider cooldown |
| Manual threat investigation | POST /api/threat/manual-lookup |
Protected; explicitly sends one public IP to selected providers |
| AI configuration | GET /api/config/ai |
Protected; returns key-set flags, never key values |
| AI configuration | POST /api/config/ai |
Protected; saves provider, models, endpoint, and cloud keys |
| AI configuration | POST /api/ai/models |
Protected; discovers Bedrock model/profile IDs without inference |
| AI configuration | POST /api/ai/pricing/check |
Protected; checks embedded pricing coverage without provider access |
| AI configuration | POST /api/ai/guardrails |
Protected; discovers Bedrock guardrails without inference (fail-open) |
| AI configuration | POST /api/ai/test |
Protected; retrieves model IDs without sending network data |
| AI insights | GET /api/ai/facts |
Protected; local facts and prior-period comparison only |
| AI insights | GET /api/ai/usage/monthly |
Protected; current and previous local-month token usage and approximate USD cost |
| AI insights | GET /api/ai/pricing/diagnostics |
Protected; selected-model status and grouped unpriced usage |
| AI insights | POST /api/ai/analyze |
Protected; manually analyzes aggregates (incl. destination IPs, hostnames, device names, MAC); cloud requires double consent |
| AI notifications | GET /api/ai/notification-config |
Protected; returns schedule, trigger, destination, and runtime status |
| AI notifications | POST /api/ai/notification-config |
Protected; saves validated scheduling and automation consent settings |
| AI notifications | GET /api/ai/notification-events |
Protected; returns up to 200 append-only delivery records |
| AI notifications | POST /api/ai/notification-test |
Protected; tests UI/Slack delivery without invoking AI |
| AI notifications | POST /api/ai/notification-run-now |
Protected; explicitly runs the configured analysis range |
| AI chat | POST /api/ai/chat |
Protected; appends the question first and stores an answer or failure row |
| AI chat | GET /api/ai/conversations |
Protected; conversation list and storage usage |
| AI chat | GET /api/ai/conversations/:id |
Protected; message history preserved across restarts |
| AI chat | DELETE /api/ai/conversations/:id |
Protected; explicit conversation-level deletion |
| Slack | POST /api/slack/test |
Protected |
| Slack | POST /api/slack/verify |
Protected |
| Slack | POST /api/slack/lookup-user |
Protected |
| Detection log | GET /api/notification-log |
Protected |
| Beacons | GET /api/beacons |
Protected |
| Beacons | GET /api/beacons/config |
Protected |
| Beacons | POST /api/beacons/config |
Protected |
| Beacons | POST /api/beacons/:id/dismiss |
Protected |