33 KiB
Route Access Inventory
This document publishes the checked Hono API route access classification from apps/api/src/route-access-inventory.ts. It is a static security review aid only: it records route boundaries, access classes, rationale, and redacted data-sensitivity notes without changing route handlers, OpenAPI metadata, authorization middleware, or runtime behavior.
Historical-plan note: route keys and access classes in this document are current only when the focused verification below passes. Do not copy route paths from older improvement-plan files into this inventory without confirming the typed source of truth.
Scope and Source of Truth
- Source of truth:
apps/api/src/route-access-inventory.ts. - Scanner reference:
tools/api-inventory/scan-api-routes.tsdiscoversapp.get/post/patch/deleteroute registrations fromapps/api/src/app.tsfor coverage checks. - Verification:
apps/api/src/route-access-inventory.test.tschecks scanner-discovered route coverage and OpenAPI security expectations;apps/api/src/route-access-inventory-doc.test.tschecks this document for drift. - Route keys are written as
METHOD pathand must match the typed inventory exactly once. - This inventory covers all current Hono API routes, including health, documentation, authentication, analytics, platform-lead ingestion, accounts, usage, notifications, workspaces, entity, relationship, export, webhook, and maintenance surfaces.
- Adjacent coverage:
docs/security/csrf-inventory.mddocuments CSRF posture and mutating API route classes. This document references that coverage but does not duplicate its mutating-route-only table.
Redaction Rules
- Do not include tokens, plaintext credentials, fixture tenant identifiers, customer data, environment variable values, or concrete database identifiers.
- Keep sensitive-data notes categorical and redacted, for example “returns aggregate counts” or “consumes uploaded file content.”
- Do not paste authorization headers, JWTs, API keys, passwords, emails, tenant fixtures, or customer examples into this document.
- Route parameters such as
:entity,:rowId, and:idare schema placeholders, not real identifiers.
Access Class Legend
| Class | Boundary |
|---|---|
public-health |
Unauthenticated infrastructure health or readiness endpoint exposing only service/dependency status metadata. |
public-docs |
Unauthenticated API documentation or schema discovery surface exposing schema metadata only. |
service-token |
Service/API-token style boundary, including stored API key or service credential checks where implemented. |
platform-source-credential |
Pre-tenant platform-lead boundary using a rotatable, source-scoped bearer capability that selects only its configured source. |
service-or-tenant-api-key |
Service credential or tenant-bound stored API-key boundary with route-specific tenant and permission checks. |
optional-api-key-validation |
Public validation helper that optionally accepts a presented stored API key or service token and returns redacted validation status. |
tenant-api-key |
Tenant-bound stored API-key boundary where the credential scopes the tenant and available usage metadata. |
tenant-webhook-credential |
Tenant-bound incoming webhook credential boundary using a stored API key, hashed webhook token, or HMAC signature tied to a tenant endpoint. |
provider-body-token-webhook |
Provider webhook ingress authenticated by a bounded write-only token in the request body, resolved through a stored hash and re-verified against the encrypted connection credential before tenant-bound processing. |
provider-header-token-webhook |
Provider webhook ingress authenticated by a bounded write-only bearer token in a request header, resolved through a stored hash and re-verified against the encrypted connection credential before tenant-bound processing. |
provider-hmac-webhook |
Provider webhook ingress authenticated with the provider-specific HMAC contract over the exact bounded request body before identity context binding or persistence. |
jwt-auth |
Bearer JWT authenticated user boundary. |
auth-credential-exchange |
Public credential exchange that consumes submitted credentials and issues authenticated API state after validation. |
public-analytics-token |
Browser-facing anonymous analytics ingestion capability; it never authorizes analytics reads or identity attribution. |
public-analytics-overview |
Unauthenticated tenantless aggregate read enabled only by the operator-controlled public analytics setting and isolated platform analytics RLS context. |
webhook-signature |
Signed webhook ingress boundary that verifies provider signing headers before processing an addressed webhook retry. |
provider-refetch-webhook |
Provider webhook ingress that trusts only an opaque provider object id, refetches the authoritative record from the provider server-side, and syncs redacted tenant-scoped metadata instead of the posted payload. |
canonical-redirect |
Runtime-only compatibility shim that redirects removed API-prefix requests to the canonical API path without reading request data. |
Full Route Access Table
| Route | Access class | Sensitive data note | Rationale |
|---|---|---|---|
GET /healthz |
public-health |
No sensitive data. | Unauthenticated liveness probe returns only service status and request correlation metadata. |
GET /readyz |
public-health |
Dependency health state is exposed without implementation details. | Unauthenticated readiness probe returns redacted dependency status for infrastructure checks. |
GET /v1/health |
public-health |
No sensitive data. | Versioned liveness probe returns only service status and request correlation metadata. |
GET /v1/openapi.json |
public-docs |
No sensitive data. | OpenAPI discovery is intentionally public for client integration and contains schema metadata only. |
GET /v1/docs |
public-docs |
No sensitive data. | Documentation shell is intentionally public and renders the OpenAPI document without runtime data. |
GET /v1/session/current-user |
service-token |
Returns authenticated principal type metadata only. | Current service principal endpoint requires a bearer service token before returning authentication state. |
POST /v1/auth/login |
auth-credential-exchange |
Consumes credentials and returns a JWT plus basic user identity. | Login exchanges submitted email and password credentials for a short-lived JWT after password verification. |
POST /v1/auth/refresh-token |
jwt-auth |
Returns a JWT plus basic user identity. | Refresh requires an existing bearer JWT before issuing a replacement token for the same user. |
POST /v1/auth/logout |
jwt-auth |
Consumes JWT credential material but returns only a success envelope and expired cookie attributes. | Logout requires an existing bearer JWT before revoking the active API session and clearing the API cookie. |
POST /v1/api-keys/validate |
optional-api-key-validation |
Returns redacted stored API-key metadata but never plaintext key material. | API-key validation optionally accepts a presented stored API key or service token and reports redacted validation status without requiring a prior credential. |
POST /v1/platform/leads |
platform-source-credential |
Consumes bounded platform lead contact and attribution data while omitting source capability material and submitted lead data from responses and diagnostics. | Platform lead ingestion requires a rotatable, source-scoped bearer capability; the authenticated capability selects the configured source and is revalidated atomically during pre-tenant persistence. |
POST /v1/support/inbound-email |
webhook-signature |
Consumes signed email metadata and message body while omitting provider payloads and signing material from responses. | Inbound support email verifies Mailjet webhook signing headers before resolving tenant inbound addresses and creating tickets. |
POST /v1/email/inbound-mailjet |
webhook-signature |
Consumes signed email metadata and message body while omitting provider payloads, recipient content, and signing material from responses. | Tenant inbound email verifies Mailjet webhook signing headers before resolving tenant inbound addresses and creating lead/activity records. |
POST /v1/analytics/events |
public-analytics-token |
Consumes an anonymous analytics identifier, URLs, routes, and event labels; authenticated user and portal identifiers are rejected. | Analytics event ingestion accepts only a bounded anonymous visitor identifier and writes tenantless records in the isolated platform analytics RLS context. |
POST /v1/analytics/page-views |
public-analytics-token |
Consumes an anonymous analytics identifier, URLs, and route names; authenticated user and portal identifiers are rejected. | Analytics page-view ingestion accepts only a bounded anonymous visitor identifier and writes tenantless records in the isolated platform analytics RLS context. |
GET /v1/analytics/public |
public-analytics-overview |
Returns tenantless aggregate analytics counts and top-level chart data without user, tenant, or portal attribution. | Public analytics is enabled only by the operator-controlled setting and returns tenantless global aggregates from the isolated platform analytics RLS context. |
GET /v1/analytics/admin |
service-token |
Returns global tenantless aggregates or aggregate metrics for an explicitly tenant-bound portal scope. | Admin analytics requires service credentials plus an operator user identifier verified through the RLS-protected AdminUser row; optional portal reads require an exact tenant and portal pair. |
GET /v1/notifications/stream |
service-token |
Returns bounded, sanitized notification delivery snapshots and cursors without provider payloads, metadata, or raw delivery secrets. | Notification stream requires service credentials before returning tenant and user scoped in-app delivery diagnostics over SSE. |
GET /v1/accounts |
service-token |
Returns tenant identifiers, names, slugs, icons, and subscription summary fields without plaintext secrets. | Account listing requires service credentials before returning tenant account metadata and subscription summaries. |
GET /v1/accounts/:id |
service-token |
Returns tenant identifiers, names, slugs, icons, and subscription summary fields without plaintext secrets. | Account lookup requires service credentials before returning one tenant account metadata and subscription summary. |
GET /v1/usage |
tenant-api-key |
Returns plan and remaining API usage metadata for the credential-scoped tenant. | Usage lookups enter through the canonical API host and validate tenant API-key credentials in the API runtime. |
GET /v1/contacts |
tenant-api-key |
Returns redacted contact fields for the credential-scoped tenant; internal notes and credential material are omitted. | Public API contact reads validate a tenant-bound API-key credential before querying only that credential's tenant scope. |
GET /v1/companies |
tenant-api-key |
Returns redacted organisation contact fields for the credential-scoped tenant; internal notes and credential material are omitted. | Public API company reads validate a tenant-bound API-key credential before querying only that credential's tenant scope. |
GET /v1/deals |
tenant-api-key |
Returns redacted sales-pipeline project fields for the credential-scoped tenant; internal notes and credential material are omitted. | Public API deal reads validate a tenant-bound API-key credential before querying only that credential's tenant scope. |
GET /v1/projects |
tenant-api-key |
Returns redacted project fields for the credential-scoped tenant; internal notes and credential material are omitted. | Public API project reads validate a tenant-bound API-key credential before querying only that credential's tenant scope. |
GET /v1/tasks |
tenant-api-key |
Returns redacted task fields for the credential-scoped tenant; internal notes and credential material are omitted. | Public API task reads validate a tenant-bound API-key credential before querying only that credential's tenant scope. |
GET /v1/leads |
tenant-api-key |
Returns redacted lead-inbox fields for the credential-scoped tenant; raw payloads, anti-spam internals and credential material are omitted. | Public API lead reads validate a tenant-bound API-key credential before querying only that credential's tenant scope. |
POST /v1/webhooks/incoming/:tenant/:slug |
tenant-webhook-credential |
Consumes third-party lead payloads and stores redacted ingestion metadata; API keys, webhook tokens, HMAC material and raw signing secrets are omitted from responses. | Incoming public webhooks enter through the canonical API host, resolve the tenant endpoint, validate the endpoint credential mode and create only tenant-scoped lead intake records. |
POST /v1/webhooks/telephony/aircall |
provider-body-token-webhook |
Consumes bounded call lifecycle metadata and a write-only provider token; responses disclose no tenant, credential, rate-limit, or deduplication state. | Aircall webhook ingress authenticates the provider-issued body token against its stored hash, resolves exactly one tenant connection, and re-verifies the encrypted connection credential before RLS-scoped persistence. |
POST /v1/webhooks/telephony/hallopetra |
provider-header-token-webhook |
Consumes bounded post-call metadata and a write-only webhook secret; responses disclose no tenant, credential, rate-limit, or deduplication state, and native transcripts are not persisted. | HalloPetra webhook ingress authenticates the dedicated bearer secret against its stored hash, resolves exactly one tenant connection, and re-verifies the encrypted connection credential before RLS-scoped persistence. |
POST /v1/webhooks/admin-telephony/aircall |
provider-body-token-webhook |
Consumes bounded call lifecycle metadata and a write-only provider token; neutral responses disclose no AdminUser, connection, credential, rate-limit, or deduplication state. | Admin Aircall webhook ingress authenticates the provider-issued body token against its stored hash, resolves one active AdminUser connection, and binds that AdminUser RLS context before idempotent persistence. |
POST /v1/billing/lago/webhooks |
provider-hmac-webhook |
Consumes tenant-scoped subscription lifecycle metadata while responses omit customer identifiers, provider object identifiers, payloads, and signing material. | Lago billing webhook ingress verifies the provider HMAC over the exact request body before binding the embedded customer tenant and applying replay-safe subscription state changes. |
POST /v1/billing/mollie/webhooks |
provider-refetch-webhook |
Consumes a provider payment id and stores redacted billing lifecycle metadata without returning provider payloads or plaintext credentials. | Mollie billing webhook ingress accepts only the provider payment id, refetches that payment from Mollie server-side, and syncs only tenant-scoped billing metadata from the verified payment. |
POST /v1/email-sequences/mailjet/webhooks |
webhook-signature |
Consumes signed delivery event metadata while responses omit provider payloads, recipient data, and signing material. | Email-sequence provider webhooks verify Mailjet signing headers before correlating bounce events to provider message ids. |
POST /v1/admin-sales/email/provider-events |
provider-hmac-webhook |
Consumes bounded delivery and engagement metadata while responses omit recipient data, provider payloads, signing material, and AdminUser identifiers. | Provider-neutral admin email events require a timestamp-bound HMAC over the exact request body before an AdminUser RLS context is bound and an idempotent event is persisted. |
POST /v1/admin-sales/email/bcc-inbound |
webhook-signature |
Consumes bounded email headers and bodies while responses omit message content, recipient capability material, signing material, and AdminUser identifiers. | Admin BCC ingestion requires provider authentication and one exact signed, rotatable BCC capability before binding the embedded AdminUser RLS context. |
GET /v1/workspaces/:tenantId/auth/providers |
service-token |
Returns redacted OIDC/SAML provider metadata only; client secrets, SAML certificate bodies, private keys, token hashes, invite tokens, and raw metadata documents are omitted. | Workspace auth-provider discovery requires a service token before returning tenant-scoped SSO metadata. |
POST /v1/workspaces/:tenantId/context/revalidate |
service-token |
Consumes tenant and user identifiers and returns a redacted validity envelope without provider secrets, invite tokens, token hashes, or SSO secret material. | Workspace context revalidation requires a service token before confirming tenant/user membership for a context switch. |
GET /v1/workspaces/:tenantId/invites |
service-token |
Returns invite recipient details, lifecycle timestamps, audit user ids, and tokenPrefix only; plaintext tokens and token hashes are omitted. | Workspace invite listing requires a service token before returning tenant-scoped invite lifecycle state. |
POST /v1/workspaces/:tenantId/invites |
service-token |
Consumes invite recipient details and returns the one-time plaintext invite token only in the create response. | Workspace invite creation requires a service token before issuing a tenant-scoped invite token. |
POST /v1/workspaces/:tenantId/invites/:inviteId/accept |
service-token |
Consumes plaintext invite token and returns redacted invite lifecycle metadata without echoing the token. | Workspace invite acceptance requires a service token and a one-time invite token before finalizing tenant membership invitation state. |
POST /v1/workspaces/:tenantId/invites/:inviteId/revoke |
service-token |
Consumes revoke audit metadata and returns redacted invite lifecycle metadata without token material. | Workspace invite revocation requires a service token before finalizing the tenant-scoped invite as revoked. |
POST /v1/events/webhooks/attempts/:id |
webhook-signature |
Consumes signed webhook delivery metadata and an attempt id while omitting provider payloads and signing material from responses. | Webhook retry verifies Mailjet webhook signing headers before looking up or queueing a known delivery attempt. |
POST /v1/maintenance/export-retention/enqueue |
service-token |
Consumes an optional bounded batch size and returns only queue task metadata plus request correlation. | Export artifact retention cleanup is an operator maintenance action and requires service credentials before enqueueing work. |
GET /v1/exports/:exportJobId/download-url |
service-or-tenant-api-key |
Returns a signed artifact URL envelope without artifact bucket/key values, storage credentials, pause reason internals, filters, or object bodies. | Export download URL creation requires service credentials or a tenant-bound stored API key and blocks compliance-paused exports before returning a short-lived signed artifact URL envelope. |
GET /v1/exports/:exportJobId/progress |
service-or-tenant-api-key |
Returns export progress envelope (status, percent, rowCount) — no artifact URLs, no compliance-pause internals, no filters. | Export progress polling requires service credentials or a tenant-bound stored API key; the handler scopes lookups to the caller's tenant and never leaks artifact bucket/key details. |
POST /v1/devices/register |
jwt-auth |
Persists a sensitive device-bound push token; the response contains registration metadata only and never returns the raw token. | Derives the owner exclusively from a verified active API-session JWT; body/header identity overrides are rejected and an optional tenant is membership-revalidated before tenant/user RLS binding. |
POST /v1/devices/revoke |
jwt-auth |
Foreign user or tenant tokens are treated as not found; the response never echoes the raw token or provider internals. | Derives the owner exclusively from a verified active API-session JWT; an optional tenant is membership-revalidated before the ownership-constrained RLS write. |
GET /status |
public-health |
Boolean health state and deployment region tag only — no connection strings, hostnames or stack traces. | Unauthenticated status probe for external uptime monitors. Returns boolean-only health, revision, region, uptime. |
GET /metrics |
service-token |
Prom text-format counters and gauges — includes business KPIs (AI tokens, mail, webhook, queue depth). Token-protected. | Prometheus scrape endpoint requires bearer METRICS_TOKEN. Returns 404 when METRICS_ENABLED is false. |
Verification Commands
Run focused verification from the repository root after changing Hono routes, OpenAPI security metadata, the typed route access inventory, or this document:
pnpm exec vitest run apps/api/src/route-access-inventory.test.ts apps/api/src/route-access-inventory-doc.test.ts
pnpm exec eslint apps/api/src/route-access-inventory.ts apps/api/src/route-access-inventory.test.ts apps/api/src/route-access-inventory-doc.test.ts --max-warnings=0
Expected diagnostics name stale or missing route keys in METHOD path form, OpenAPI security drift, redaction matches, and missing required section headings by heading text.