Reference

Server API and OpenAPI

Edit page
Discover Customer Portal endpoints and build authenticated, tenant-scoped feature APIs.

Customer Portal uses Nitro file-based handlers. The assembled application generates its API reference from the handlers present in portal core and every enabled feature layer.

Discover a deployed API

Each running portal exposes:

RoutePurpose
/api-docsScalar interactive API browser.
/api-docs/swaggerSwagger UI for the same document.
/api-docs/openapi.jsonOrdered OpenAPI document enriched with Better Auth operations and shared contracts.
/api-docs/openapi.raw.jsonNitro's unmerged generated document, intended for internal assembly.

Use the ordered /api-docs/openapi.json document for clients and reviews. It reflects the layers installed in that deployment, so it is more authoritative than a copied endpoint list.

The interactive API uses the current browser session and its permissions. It is not an anonymous administration API, and successful calls still depend on the active organization and feature policy.

Current product surface

At the documented master revision, the assembled repository contains 111 Nitro API handler files. The count is a review signal rather than an API version: a catch-all handler can contribute multiple OpenAPI operations, and a handler can respond to one method only.

Owning layerHandler filesRoute familiesPrimary responsibility
core3/api/auth/**, /api/notificationsBetter Auth transport, current permissions, and notification feed
ui0Neutral presentation only
authentication0Uses core identity handlers and owns only account-entry UI
organizations10/api/organizations/**, /api/profileProfile, invitations, organization details, and email-provider credentials
administration14/api/admin/**Installation-wide users, organizations, memberships, invitations, and roles
service-requests8/api/service-requests/**Customer and organization-administrator request workflows
timesheets76/api/timesheets/**Entry, timers, setup, approvals, reporting, clients, invoices, PDFs, email, and cross-organization access
preset0Composition only
kit0Configuration and migration CLI only

CI compares these layer and handler counts with the pinned public repository tree. When the product source pin changes, a mismatch requires the inventory and relevant narrative documentation to be reviewed together. For the exact operations, parameters, and response schemas in a deployment, use its generated OpenAPI document.

Authentication and tenancy

Most product handlers are session APIs rather than token-based public APIs. A protected feature operation should:

  1. require an authenticated session;
  2. derive the active organization from that session;
  3. evaluate a typed feature action against the user's organization role;
  4. scope every tenant-owned query by the returned organization ID;
  5. validate path, query, and body input before repository access.
layers/example/server/api/example/index.post.ts
import { definePortalRouteMeta, requireFeatureAccess } from '@nuxt-customer-portal/core/server'
import { exampleFeature } from '../../../shared/feature'
import { createExampleSchema } from '../../utils/example-validation'

definePortalRouteMeta({
  openAPI: {
    tags: ['Example'],
    operationId: 'exampleCreate',
    summary: 'Create an example record',
    description: 'Creates a record in the active organization.'
  },
  body: createExampleSchema
})

export default defineEventHandler(async (event) => {
  const { session, organizationId } = await requireFeatureAccess(
    event,
    exampleFeature.policy,
    'create'
  )
  const input = createExampleSchema.parse(await readBody(event))

  return createExample({
    ...input,
    organizationId,
    createdById: session.user.id
  })
})

Do not accept organizationId from a normal browser request when the active session already determines the tenant. Administrative cross-organization operations require a separate, explicit system-administrator check.

OpenAPI metadata

Every contributor-owned handler should call definePortalRouteMeta() beside the route with:

  • one stable, unique operationId;
  • a domain tag such as Timesheets or Service requests;
  • an imperative summary;
  • a description that states authentication, tenant scope, and the relevant permission;
  • request and response schemas when Nitro cannot infer enough detail.

Keep the metadata beside the handler so moving or removing a layer also moves or removes its API description.

Error semantics

Core adapters establish these baseline responses:

StatusMeaning
400The session has no active organization or validated input is invalid.
401No authenticated user session.
403The user lacks organization membership or the required feature action.
404A scoped record does not exist or is not visible in the active organization.
409The requested transition conflicts with current domain state.

Feature repositories should avoid revealing whether a record exists in another organization. Validation failures should be useful to the caller without exposing secrets, SQL, or credentials.

Stability

The generated OpenAPI document describes the current deployment; it is not yet a versioned public API guarantee. Pin the Customer Portal commit used by an integration and review the document when upgrading. See Compatibility and releases.